@ -717,7 +717,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
}
class SmartHttpFetchConnection extends BasePackFetchConnection {
private Service svc ;
private MultiRequest Service svc ;
SmartHttpFetchConnection ( final InputStream advertisement )
throws TransportException {
@ -734,8 +734,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
final Collection < Ref > want , final Set < ObjectId > have )
throws TransportException {
try {
svc = new Service ( SVC_UPLOAD_PACK ) ;
init ( svc . in , svc . out ) ;
svc = new MultiRequest Service( SVC_UPLOAD_PACK ) ;
init ( svc . getInputStream ( ) , svc . getOutputStream ( ) ) ;
super . doFetch ( monitor , want , have ) ;
} finally {
svc = null ;
@ -762,57 +762,36 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
protected void doPush ( final ProgressMonitor monitor ,
final Map < String , RemoteRefUpdate > refUpdates )
throws TransportException {
final Service svc = new Service ( SVC_RECEIVE_PACK ) ;
init ( svc . in , svc . out ) ;
final Service svc = new MultiRequest Service( SVC_RECEIVE_PACK ) ;
init ( svc . getInputStream ( ) , svc . getOutputStream ( ) ) ;
super . doPush ( monitor , refUpdates ) ;
}
}
/ * *
* State required to speak multiple HTTP requests with the remote .
* < p >
* A service wrapper provides a normal looking InputStream and OutputStream
* pair which are connected via HTTP to the named remote service . Writing to
* the OutputStream is buffered until either the buffer overflows , or
* reading from the InputStream occurs . If overflow occurs HTTP / 1 . 1 and its
* chunked transfer encoding is used to stream the request data to the
* remote service . If the entire request fits in the memory buffer , the
* older HTTP / 1 . 0 standard and a fixed content length is used instead .
* < p >
* It is an error to attempt to read without there being outstanding data
* ready for transmission on the OutputStream .
* < p >
* No state is preserved between write - read request pairs . The caller is
* responsible for replaying state vector information as part of the request
* data written to the OutputStream . Any session HTTP cookies may or may not
* be preserved between requests , it is left up to the JVM ' s implementation
* of the HTTP client .
* /
class Service {
private final String serviceName ;
/** Basic service for sending and receiving HTTP requests. */
abstract class Service {
protected final String serviceName ;
private final String requestType ;
protected final String requestType ;
private final String responseType ;
protected final String responseType ;
private final HttpExecuteStream execute ;
protected HttpURLConnection conn ;
boolean finalReques t;
protected HttpOutputStream out ;
final UnionInputStream in ;
protected final HttpExecuteStream execute ;
final HttpOutputStream out ;
HttpURLConnection conn ;
final UnionInputStream in ;
Service ( final String serviceName ) {
Service ( String serviceName ) {
this . serviceName = serviceName ;
this . requestType = "application/x-" + serviceName + "-request" ; //$NON-NLS-1$ //$NON-NLS-2$
this . responseType = "application/x-" + serviceName + "-result" ; //$NON-NLS-1$ //$NON-NLS-2$
this . out = new HttpOutputStream ( ) ;
this . execute = new HttpExecuteStream ( ) ;
this . in = new UnionInputStream ( execute ) ;
this . out = new HttpOutputStream ( ) ;
}
void openStream ( ) throws IOException {
@ -823,50 +802,34 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
conn . setRequestProperty ( HDR_ACCEPT , responseType ) ;
}
void execute ( ) throws IOException {
out . close ( ) ;
if ( conn = = null ) {
if ( out . length ( ) = = 0 ) {
// Request output hasn't started yet, but more data is being
// requested. If there is no request data buffered and the
// final request was already sent, do nothing to ensure the
// caller is shown EOF on the InputStream; otherwise an
// programming error has occurred within this module.
if ( finalRequest )
return ;
throw new TransportException ( uri ,
JGitText . get ( ) . startingReadStageWithoutWrittenRequestDataPendingIsNotSupported ) ;
}
// Try to compress the content, but only if that is smaller.
TemporaryBuffer buf = new TemporaryBuffer . Heap ( http . postBuffer ) ;
try {
GZIPOutputStream gzip = new GZIPOutputStream ( buf ) ;
out . writeTo ( gzip , null ) ;
gzip . close ( ) ;
if ( out . length ( ) < buf . length ( ) )
buf = out ;
} catch ( IOException err ) {
// Most likely caused by overflowing the buffer, meaning
// its larger if it were compressed. Don't compress.
void sendRequest ( ) throws IOException {
// Try to compress the content, but only if that is smaller.
TemporaryBuffer buf = new TemporaryBuffer . Heap ( http . postBuffer ) ;
try {
GZIPOutputStream gzip = new GZIPOutputStream ( buf ) ;
out . writeTo ( gzip , null ) ;
gzip . close ( ) ;
if ( out . length ( ) < buf . length ( ) )
buf = out ;
}
openStream ( ) ;
if ( buf ! = out )
conn . setRequestProperty ( HDR_CONTENT_ENCODING , ENCODING_GZIP ) ;
conn . setFixedLengthStreamingMode ( ( int ) buf . length ( ) ) ;
final OutputStream httpOut = conn . getOutputStream ( ) ;
try {
buf . writeTo ( httpOut , null ) ;
} finally {
httpOut . close ( ) ;
}
} catch ( IOException err ) {
// Most likely caused by overflowing the buffer, meaning
// its larger if it were compressed. Don't compress.
buf = out ;
}
out . reset ( ) ;
openStream ( ) ;
if ( buf ! = out )
conn . setRequestProperty ( HDR_CONTENT_ENCODING , ENCODING_GZIP ) ;
conn . setFixedLengthStreamingMode ( ( int ) buf . length ( ) ) ;
final OutputStream httpOut = conn . getOutputStream ( ) ;
try {
buf . writeTo ( httpOut , null ) ;
} finally {
httpOut . close ( ) ;
}
}
void openResponse ( ) throws IOException {
final int status = HttpSupport . response ( conn ) ;
if ( status ! = HttpURLConnection . HTTP_OK ) {
throw new TransportException ( uri , status + " " //$NON-NLS-1$
@ -878,26 +841,18 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
conn . getInputStream ( ) . close ( ) ;
throw wrongContentType ( responseType , contentType ) ;
}
in . add ( openInputStream ( conn ) ) ;
if ( ! finalRequest )
in . add ( execute ) ;
conn = null ;
}
class HttpOutputStream extends TemporaryBuffer {
HttpOutputStream ( ) {
super ( http . postBuffer ) ;
}
HttpOutputStream getOutputStream ( ) {
return out ;
}
@Override
protected OutputStream overflow ( ) throws IOException {
openStream ( ) ;
conn . setChunkedStreamingMode ( 0 ) ;
return conn . getOutputStream ( ) ;
}
InputStream getInputStream ( ) {
return in ;
}
abstract void execute ( ) throws IOException ;
class HttpExecuteStream extends InputStream {
public int read ( ) throws IOException {
execute ( ) ;
@ -914,6 +869,98 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
return 0 ;
}
}
class HttpOutputStream extends TemporaryBuffer {
HttpOutputStream ( ) {
super ( http . postBuffer ) ;
}
@Override
protected OutputStream overflow ( ) throws IOException {
openStream ( ) ;
conn . setChunkedStreamingMode ( 0 ) ;
return conn . getOutputStream ( ) ;
}
}
}
/ * *
* State required to speak multiple HTTP requests with the remote .
* < p >
* A service wrapper provides a normal looking InputStream and OutputStream
* pair which are connected via HTTP to the named remote service . Writing to
* the OutputStream is buffered until either the buffer overflows , or
* reading from the InputStream occurs . If overflow occurs HTTP / 1 . 1 and its
* chunked transfer encoding is used to stream the request data to the
* remote service . If the entire request fits in the memory buffer , the
* older HTTP / 1 . 0 standard and a fixed content length is used instead .
* < p >
* It is an error to attempt to read without there being outstanding data
* ready for transmission on the OutputStream .
* < p >
* No state is preserved between write - read request pairs . The caller is
* responsible for replaying state vector information as part of the request
* data written to the OutputStream . Any session HTTP cookies may or may not
* be preserved between requests , it is left up to the JVM ' s implementation
* of the HTTP client .
* /
class MultiRequestService extends Service {
boolean finalRequest ;
MultiRequestService ( final String serviceName ) {
super ( serviceName ) ;
}
/** Keep opening send-receive pairs to the given URI. */
@Override
void execute ( ) throws IOException {
out . close ( ) ;
if ( conn = = null ) {
if ( out . length ( ) = = 0 ) {
// Request output hasn't started yet, but more data is being
// requested. If there is no request data buffered and the
// final request was already sent, do nothing to ensure the
// caller is shown EOF on the InputStream; otherwise an
// programming error has occurred within this module.
if ( finalRequest )
return ;
throw new TransportException ( uri ,
JGitText . get ( ) . startingReadStageWithoutWrittenRequestDataPendingIsNotSupported ) ;
}
sendRequest ( ) ;
}
out . reset ( ) ;
openResponse ( ) ;
in . add ( openInputStream ( conn ) ) ;
if ( ! finalRequest )
in . add ( execute ) ;
conn = null ;
}
}
/** Service for maintaining a single long-poll connection. */
class LongPollService extends Service {
/ * *
* @param serviceName
* /
LongPollService ( String serviceName ) {
super ( serviceName ) ;
}
/** Only open one send-receive request. */
@Override
void execute ( ) throws IOException {
out . close ( ) ;
if ( conn = = null )
sendRequest ( ) ;
openResponse ( ) ;
in . add ( openInputStream ( conn ) ) ;
}
}
private static class DummyX509TrustManager implements X509TrustManager {