You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PacketLineOut.java 6.1KB

Client-side protocol V2 support for fetching Make all transports request protocol V2 when fetching. Depending on the transport, set the GIT_PROTOCOL environment variable (file and ssh), pass the Git-Protocol header (http), or set the hidden "\0version=2\0" (git anon). We'll fall back to V0 if the server doesn't reply with a version 2 answer. A user can control which protocol the client requests via the git config protocol.version; if not set, JGit requests protocol V2 for fetching. Pushing always uses protocol V0 still. In the API, there is only a new Transport.openFetch() version that takes a collection of RefSpecs plus additional patterns to construct the Ref prefixes for the "ls-refs" command in protocol V2. If none are given, the server will still advertise all refs, even in protocol V2. BasePackConnection.readAdvertisedRefs() handles falling back to protocol V0. It newly returns true if V0 was used and the advertised refs were read, and false if V2 is used and an explicit "ls-refs" is needed. (This can't be done transparently inside readAdvertisedRefs() because a "stateless RPC" transport like TransportHttp may need to open a new connection for writing.) BasePackFetchConnection implements the changes needed for the protocol V2 "fetch" command (stateless protocol, simplified ACK handling, delimiters, section headers). In TransportHttp, change readSmartHeaders() to also recognize the "version 2" packet line as a valid smart server indication. Adapt tests, and run all the HTTP tests not only with both HTTP connection factories (JDK and Apache HttpClient) but also with both protocol V0 and V2. The SSH tests are much slower and much more focused on the SSH protocol and SSH key handling. Factor out two very simple cloning and pulling tests and make those run with protocol V2. Bug: 553083 Change-Id: I357c7f5daa7efb2872f1c64ee6f6d54229031ae1 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
3 years ago
Client-side protocol V2 support for fetching Make all transports request protocol V2 when fetching. Depending on the transport, set the GIT_PROTOCOL environment variable (file and ssh), pass the Git-Protocol header (http), or set the hidden "\0version=2\0" (git anon). We'll fall back to V0 if the server doesn't reply with a version 2 answer. A user can control which protocol the client requests via the git config protocol.version; if not set, JGit requests protocol V2 for fetching. Pushing always uses protocol V0 still. In the API, there is only a new Transport.openFetch() version that takes a collection of RefSpecs plus additional patterns to construct the Ref prefixes for the "ls-refs" command in protocol V2. If none are given, the server will still advertise all refs, even in protocol V2. BasePackConnection.readAdvertisedRefs() handles falling back to protocol V0. It newly returns true if V0 was used and the advertised refs were read, and false if V2 is used and an explicit "ls-refs" is needed. (This can't be done transparently inside readAdvertisedRefs() because a "stateless RPC" transport like TransportHttp may need to open a new connection for writing.) BasePackFetchConnection implements the changes needed for the protocol V2 "fetch" command (stateless protocol, simplified ACK handling, delimiters, section headers). In TransportHttp, change readSmartHeaders() to also recognize the "version 2" packet line as a valid smart server indication. Adapt tests, and run all the HTTP tests not only with both HTTP connection factories (JDK and Apache HttpClient) but also with both protocol V0 and V2. The SSH tests are much slower and much more focused on the SSH protocol and SSH key handling. Factor out two very simple cloning and pulling tests and make those run with protocol V2. Bug: 553083 Change-Id: I357c7f5daa7efb2872f1c64ee6f6d54229031ae1 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (C) 2008, 2010 Google Inc.
  3. * Copyright (C) 2008, 2009 Robin Rosenberg <robin.rosenberg@dewire.com>
  4. * Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
  5. *
  6. * This program and the accompanying materials are made available under the
  7. * terms of the Eclipse Distribution License v. 1.0 which is available at
  8. * https://www.eclipse.org/org/documents/edl-v10.php.
  9. *
  10. * SPDX-License-Identifier: BSD-3-Clause
  11. */
  12. package org.eclipse.jgit.transport;
  13. import static java.nio.charset.StandardCharsets.UTF_8;
  14. import java.io.IOException;
  15. import java.io.OutputStream;
  16. import org.eclipse.jgit.lib.Constants;
  17. import org.eclipse.jgit.util.RawParseUtils;
  18. import org.slf4j.Logger;
  19. import org.slf4j.LoggerFactory;
  20. /**
  21. * Write Git style pkt-line formatting to an output stream.
  22. * <p>
  23. * This class is not thread safe and may issue multiple writes to the underlying
  24. * stream for each method call made.
  25. * <p>
  26. * This class performs no buffering on its own. This makes it suitable to
  27. * interleave writes performed by this class with writes performed directly
  28. * against the underlying OutputStream.
  29. */
  30. public class PacketLineOut {
  31. private static final Logger log = LoggerFactory.getLogger(PacketLineOut.class);
  32. private final OutputStream out;
  33. private final byte[] lenbuffer;
  34. private boolean flushOnEnd;
  35. private boolean usingSideband;
  36. /**
  37. * Create a new packet line writer.
  38. *
  39. * @param outputStream
  40. * stream.
  41. */
  42. public PacketLineOut(OutputStream outputStream) {
  43. out = outputStream;
  44. lenbuffer = new byte[5];
  45. flushOnEnd = true;
  46. }
  47. /**
  48. * Set the flush behavior during {@link #end()}.
  49. *
  50. * @param flushOnEnd
  51. * if true, a flush-pkt written during {@link #end()} also
  52. * flushes the underlying stream.
  53. */
  54. public void setFlushOnEnd(boolean flushOnEnd) {
  55. this.flushOnEnd = flushOnEnd;
  56. }
  57. /**
  58. * @return whether to add a sideband designator to each non-flush and
  59. * non-delim packet
  60. * @see #setUsingSideband
  61. * @since 5.5
  62. */
  63. public boolean isUsingSideband() {
  64. return usingSideband;
  65. }
  66. /**
  67. * @param value If true, when writing packet lines, add, as the first
  68. * byte, a sideband designator to each non-flush and non-delim
  69. * packet. See pack-protocol.txt and protocol-v2.txt from the Git
  70. * project for more information, specifically the "side-band" and
  71. * "sideband-all" sections.
  72. * @since 5.5
  73. */
  74. public void setUsingSideband(boolean value) {
  75. this.usingSideband = value;
  76. }
  77. /**
  78. * Write a UTF-8 encoded string as a single length-delimited packet.
  79. *
  80. * @param s
  81. * string to write.
  82. * @throws java.io.IOException
  83. * the packet could not be written, the stream is corrupted as
  84. * the packet may have been only partially written.
  85. */
  86. public void writeString(String s) throws IOException {
  87. writePacket(Constants.encode(s));
  88. }
  89. /**
  90. * Write a binary packet to the stream.
  91. *
  92. * @param packet
  93. * the packet to write; the length of the packet is equal to the
  94. * size of the byte array.
  95. * @throws java.io.IOException
  96. * the packet could not be written, the stream is corrupted as
  97. * the packet may have been only partially written.
  98. */
  99. public void writePacket(byte[] packet) throws IOException {
  100. writePacket(packet, 0, packet.length);
  101. }
  102. /**
  103. * Write a binary packet to the stream.
  104. *
  105. * @param buf
  106. * the packet to write
  107. * @param pos
  108. * first index within {@code buf}.
  109. * @param len
  110. * number of bytes to write.
  111. * @throws java.io.IOException
  112. * the packet could not be written, the stream is corrupted as
  113. * the packet may have been only partially written.
  114. * @since 4.5
  115. */
  116. public void writePacket(byte[] buf, int pos, int len) throws IOException {
  117. if (usingSideband) {
  118. formatLength(len + 5);
  119. out.write(lenbuffer, 0, 4);
  120. out.write(1);
  121. } else {
  122. formatLength(len + 4);
  123. out.write(lenbuffer, 0, 4);
  124. }
  125. out.write(buf, pos, len);
  126. if (log.isDebugEnabled()) {
  127. // Escape a trailing \n to avoid empty lines in the log.
  128. if (len > 0 && buf[pos + len - 1] == '\n') {
  129. log.debug(
  130. "git> " + RawParseUtils.decode(UTF_8, buf, pos, len - 1) //$NON-NLS-1$
  131. + "\\n"); //$NON-NLS-1$
  132. } else {
  133. log.debug("git> " + RawParseUtils.decode(UTF_8, buf, pos, len)); //$NON-NLS-1$
  134. }
  135. }
  136. }
  137. /**
  138. * Write a packet delim marker (0001).
  139. *
  140. * @throws java.io.IOException
  141. * the marker could not be written, the stream is corrupted
  142. * as the marker may have been only partially written.
  143. * @since 5.0
  144. */
  145. public void writeDelim() throws IOException {
  146. formatLength(1);
  147. out.write(lenbuffer, 0, 4);
  148. log.debug("git> 0001"); //$NON-NLS-1$
  149. }
  150. /**
  151. * Write a packet end marker, sometimes referred to as a flush command.
  152. * <p>
  153. * Technically this is a magical packet type which can be detected
  154. * separately from an empty string or an empty packet.
  155. * <p>
  156. * Implicitly performs a flush on the underlying OutputStream to ensure the
  157. * peer will receive all data written thus far.
  158. *
  159. * @throws java.io.IOException
  160. * the end marker could not be written, the stream is corrupted
  161. * as the end marker may have been only partially written.
  162. */
  163. public void end() throws IOException {
  164. formatLength(0);
  165. out.write(lenbuffer, 0, 4);
  166. log.debug("git> 0000"); //$NON-NLS-1$
  167. if (flushOnEnd)
  168. flush();
  169. }
  170. /**
  171. * Flush the underlying OutputStream.
  172. * <p>
  173. * Performs a flush on the underlying OutputStream to ensure the peer will
  174. * receive all data written thus far.
  175. *
  176. * @throws java.io.IOException
  177. * the underlying stream failed to flush.
  178. */
  179. public void flush() throws IOException {
  180. out.flush();
  181. }
  182. private static final byte[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
  183. '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  184. private void formatLength(int w) {
  185. formatLength(lenbuffer, w);
  186. }
  187. static void formatLength(byte[] lenbuffer, int w) {
  188. int o = 3;
  189. while (o >= 0 && w != 0) {
  190. lenbuffer[o--] = hexchar[w & 0xf];
  191. w >>>= 4;
  192. }
  193. while (o >= 0)
  194. lenbuffer[o--] = '0';
  195. }
  196. }