summaryrefslogtreecommitdiffstats
path: root/src/org/apache/http
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit417f3b92ba4549b2f22340e3107d869d2b9c5bb8 (patch)
tree2e08a2a91d6d14995df54490e3667f7943fbc6d6 /src/org/apache/http
downloadexternal_apache-http-417f3b92ba4549b2f22340e3107d869d2b9c5bb8.zip
external_apache-http-417f3b92ba4549b2f22340e3107d869d2b9c5bb8.tar.gz
external_apache-http-417f3b92ba4549b2f22340e3107d869d2b9c5bb8.tar.bz2
Initial Contribution
Diffstat (limited to 'src/org/apache/http')
-rw-r--r--src/org/apache/http/ConnectionClosedException.java58
-rw-r--r--src/org/apache/http/ConnectionReuseStrategy.java75
-rw-r--r--src/org/apache/http/FormattedHeader.java68
-rw-r--r--src/org/apache/http/Header.java64
-rw-r--r--src/org/apache/http/HeaderElement.java59
-rw-r--r--src/org/apache/http/HeaderElementIterator.java61
-rw-r--r--src/org/apache/http/HeaderIterator.java64
-rw-r--r--src/org/apache/http/HttpClientConnection.java112
-rw-r--r--src/org/apache/http/HttpConnection.java110
-rw-r--r--src/org/apache/http/HttpConnectionMetrics.java79
-rw-r--r--src/org/apache/http/HttpEntity.java196
-rw-r--r--src/org/apache/http/HttpEntityEnclosingRequest.java63
-rw-r--r--src/org/apache/http/HttpException.java75
-rw-r--r--src/org/apache/http/HttpHost.java218
-rw-r--r--src/org/apache/http/HttpInetConnection.java55
-rw-r--r--src/org/apache/http/HttpMessage.java191
-rw-r--r--src/org/apache/http/HttpRequest.java51
-rw-r--r--src/org/apache/http/HttpRequestFactory.java51
-rw-r--r--src/org/apache/http/HttpRequestInterceptor.java69
-rw-r--r--src/org/apache/http/HttpResponse.java161
-rw-r--r--src/org/apache/http/HttpResponseFactory.java76
-rw-r--r--src/org/apache/http/HttpResponseInterceptor.java68
-rw-r--r--src/org/apache/http/HttpServerConnection.java96
-rw-r--r--src/org/apache/http/HttpStatus.java182
-rw-r--r--src/org/apache/http/HttpVersion.java104
-rw-r--r--src/org/apache/http/MalformedChunkCodingException.java59
-rw-r--r--src/org/apache/http/MethodNotSupportedException.java67
-rw-r--r--src/org/apache/http/NameValuePair.java108
-rw-r--r--src/org/apache/http/NoHttpResponseException.java58
-rw-r--r--src/org/apache/http/ParseException.java65
-rw-r--r--src/org/apache/http/ProtocolException.java72
-rw-r--r--src/org/apache/http/ProtocolVersion.java287
-rw-r--r--src/org/apache/http/ReasonPhraseCatalog.java63
-rw-r--r--src/org/apache/http/RequestLine.java53
-rw-r--r--src/org/apache/http/StatusLine.java55
-rw-r--r--src/org/apache/http/TokenIterator.java67
-rw-r--r--src/org/apache/http/UnsupportedHttpVersionException.java64
-rw-r--r--src/org/apache/http/auth/AUTH.java66
-rw-r--r--src/org/apache/http/auth/AuthScheme.java140
-rw-r--r--src/org/apache/http/auth/AuthSchemeFactory.java46
-rw-r--r--src/org/apache/http/auth/AuthSchemeRegistry.java149
-rw-r--r--src/org/apache/http/auth/AuthScope.java292
-rw-r--r--src/org/apache/http/auth/AuthState.java147
-rw-r--r--src/org/apache/http/auth/AuthenticationException.java73
-rw-r--r--src/org/apache/http/auth/BasicUserPrincipal.java90
-rw-r--r--src/org/apache/http/auth/Credentials.java49
-rw-r--r--src/org/apache/http/auth/InvalidCredentialsException.java71
-rw-r--r--src/org/apache/http/auth/MalformedChallengeException.java73
-rw-r--r--src/org/apache/http/auth/NTCredentials.java180
-rw-r--r--src/org/apache/http/auth/NTUserPrincipal.java113
-rw-r--r--src/org/apache/http/auth/UsernamePasswordCredentials.java126
-rw-r--r--src/org/apache/http/auth/package.html41
-rw-r--r--src/org/apache/http/auth/params/AuthPNames.java56
-rw-r--r--src/org/apache/http/auth/params/AuthParamBean.java47
-rw-r--r--src/org/apache/http/auth/params/AuthParams.java94
-rw-r--r--src/org/apache/http/auth/params/package.html40
-rw-r--r--src/org/apache/http/client/AuthenticationHandler.java61
-rw-r--r--src/org/apache/http/client/CircularRedirectException.java70
-rw-r--r--src/org/apache/http/client/ClientProtocolException.java60
-rw-r--r--src/org/apache/http/client/CookieStore.java76
-rw-r--r--src/org/apache/http/client/CredentialsProvider.java72
-rw-r--r--src/org/apache/http/client/HttpClient.java249
-rw-r--r--src/org/apache/http/client/HttpRequestRetryHandler.java66
-rw-r--r--src/org/apache/http/client/HttpResponseException.java51
-rw-r--r--src/org/apache/http/client/NonRepeatableRequestException.java63
-rw-r--r--src/org/apache/http/client/RedirectException.java72
-rw-r--r--src/org/apache/http/client/RedirectHandler.java79
-rw-r--r--src/org/apache/http/client/RequestDirector.java92
-rw-r--r--src/org/apache/http/client/ResponseHandler.java59
-rw-r--r--src/org/apache/http/client/UserTokenHandler.java64
-rw-r--r--src/org/apache/http/client/entity/UrlEncodedFormEntity.java76
-rw-r--r--src/org/apache/http/client/methods/AbortableHttpRequest.java91
-rw-r--r--src/org/apache/http/client/methods/HttpDelete.java76
-rw-r--r--src/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java81
-rw-r--r--src/org/apache/http/client/methods/HttpGet.java83
-rw-r--r--src/org/apache/http/client/methods/HttpHead.java83
-rw-r--r--src/org/apache/http/client/methods/HttpOptions.java105
-rw-r--r--src/org/apache/http/client/methods/HttpPost.java87
-rw-r--r--src/org/apache/http/client/methods/HttpPut.java79
-rw-r--r--src/org/apache/http/client/methods/HttpRequestBase.java182
-rw-r--r--src/org/apache/http/client/methods/HttpTrace.java82
-rw-r--r--src/org/apache/http/client/methods/HttpUriRequest.java80
-rw-r--r--src/org/apache/http/client/methods/package.html40
-rw-r--r--src/org/apache/http/client/package.html41
-rw-r--r--src/org/apache/http/client/params/AllClientPNames.java65
-rw-r--r--src/org/apache/http/client/params/AuthPolicy.java58
-rw-r--r--src/org/apache/http/client/params/ClientPNames.java139
-rw-r--r--src/org/apache/http/client/params/ClientParamBean.java92
-rw-r--r--src/org/apache/http/client/params/CookiePolicy.java66
-rw-r--r--src/org/apache/http/client/params/HttpClientParams.java101
-rw-r--r--src/org/apache/http/client/params/package.html40
-rw-r--r--src/org/apache/http/client/protocol/ClientContext.java52
-rw-r--r--src/org/apache/http/client/protocol/ClientContextConfigurer.java72
-rw-r--r--src/org/apache/http/client/protocol/RequestAddCookies.java192
-rw-r--r--src/org/apache/http/client/protocol/RequestDefaultHeaders.java74
-rw-r--r--src/org/apache/http/client/protocol/RequestProxyAuthentication.java104
-rw-r--r--src/org/apache/http/client/protocol/RequestTargetAuthentication.java105
-rw-r--r--src/org/apache/http/client/protocol/ResponseProcessCookies.java146
-rw-r--r--src/org/apache/http/client/protocol/package.html40
-rw-r--r--src/org/apache/http/client/utils/CloneUtils.java75
-rw-r--r--src/org/apache/http/client/utils/URIUtils.java209
-rw-r--r--src/org/apache/http/client/utils/URLEncodedUtils.java191
-rw-r--r--src/org/apache/http/client/utils/package.html40
-rw-r--r--src/org/apache/http/conn/BasicEofSensorWatcher.java121
-rw-r--r--src/org/apache/http/conn/BasicManagedEntity.java220
-rw-r--r--src/org/apache/http/conn/ClientConnectionManager.java129
-rw-r--r--src/org/apache/http/conn/ClientConnectionManagerFactory.java50
-rw-r--r--src/org/apache/http/conn/ClientConnectionOperator.java120
-rw-r--r--src/org/apache/http/conn/ClientConnectionRequest.java73
-rw-r--r--src/org/apache/http/conn/ConnectTimeoutException.java64
-rw-r--r--src/org/apache/http/conn/ConnectionKeepAliveStrategy.java71
-rw-r--r--src/org/apache/http/conn/ConnectionPoolTimeoutException.java62
-rw-r--r--src/org/apache/http/conn/ConnectionReleaseTrigger.java86
-rw-r--r--src/org/apache/http/conn/EofSensorInputStream.java326
-rw-r--r--src/org/apache/http/conn/EofSensorWatcher.java112
-rw-r--r--src/org/apache/http/conn/HttpHostConnectException.java57
-rw-r--r--src/org/apache/http/conn/ManagedClientConnection.java261
-rw-r--r--src/org/apache/http/conn/MultihomePlainSocketFactory.java212
-rw-r--r--src/org/apache/http/conn/OperatedClientConnection.java174
-rw-r--r--src/org/apache/http/conn/package.html91
-rw-r--r--src/org/apache/http/conn/params/ConnConnectionPNames.java65
-rw-r--r--src/org/apache/http/conn/params/ConnConnectionParamBean.java55
-rw-r--r--src/org/apache/http/conn/params/ConnManagerPNames.java73
-rw-r--r--src/org/apache/http/conn/params/ConnManagerParamBean.java62
-rw-r--r--src/org/apache/http/conn/params/ConnManagerParams.java169
-rw-r--r--src/org/apache/http/conn/params/ConnPerRoute.java51
-rw-r--r--src/org/apache/http/conn/params/ConnPerRouteBean.java114
-rw-r--r--src/org/apache/http/conn/params/ConnRoutePNames.java84
-rw-r--r--src/org/apache/http/conn/params/ConnRouteParamBean.java67
-rw-r--r--src/org/apache/http/conn/params/ConnRouteParams.java203
-rw-r--r--src/org/apache/http/conn/params/package.html40
-rw-r--r--src/org/apache/http/conn/routing/BasicRouteDirector.java181
-rw-r--r--src/org/apache/http/conn/routing/HttpRoute.java443
-rw-r--r--src/org/apache/http/conn/routing/HttpRouteDirector.java88
-rw-r--r--src/org/apache/http/conn/routing/HttpRoutePlanner.java69
-rw-r--r--src/org/apache/http/conn/routing/RouteInfo.java194
-rw-r--r--src/org/apache/http/conn/routing/RouteTracker.java439
-rw-r--r--src/org/apache/http/conn/routing/package.html62
-rw-r--r--src/org/apache/http/conn/scheme/HostNameResolver.java41
-rw-r--r--src/org/apache/http/conn/scheme/LayeredSocketFactory.java72
-rw-r--r--src/org/apache/http/conn/scheme/PlainSocketFactory.java182
-rw-r--r--src/org/apache/http/conn/scheme/Scheme.java223
-rw-r--r--src/org/apache/http/conn/scheme/SchemeRegistry.java187
-rw-r--r--src/org/apache/http/conn/scheme/SocketFactory.java138
-rw-r--r--src/org/apache/http/conn/ssl/AbstractVerifier.java343
-rw-r--r--src/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java54
-rw-r--r--src/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java62
-rw-r--r--src/org/apache/http/conn/ssl/SSLSocketFactory.java384
-rw-r--r--src/org/apache/http/conn/ssl/StrictHostnameVerifier.java69
-rw-r--r--src/org/apache/http/conn/ssl/X509HostnameVerifier.java86
-rw-r--r--src/org/apache/http/conn/ssl/package.html40
-rw-r--r--src/org/apache/http/conn/util/InetAddressUtils.java72
-rw-r--r--src/org/apache/http/cookie/ClientCookie.java67
-rw-r--r--src/org/apache/http/cookie/Cookie.java139
-rw-r--r--src/org/apache/http/cookie/CookieAttributeHandler.java78
-rw-r--r--src/org/apache/http/cookie/CookieIdentityComparator.java68
-rw-r--r--src/org/apache/http/cookie/CookieOrigin.java108
-rw-r--r--src/org/apache/http/cookie/CookiePathComparator.java81
-rw-r--r--src/org/apache/http/cookie/CookieSpec.java115
-rw-r--r--src/org/apache/http/cookie/CookieSpecFactory.java46
-rw-r--r--src/org/apache/http/cookie/CookieSpecRegistry.java160
-rw-r--r--src/org/apache/http/cookie/MalformedCookieException.java74
-rw-r--r--src/org/apache/http/cookie/SM.java48
-rw-r--r--src/org/apache/http/cookie/SetCookie.java115
-rw-r--r--src/org/apache/http/cookie/SetCookie2.java66
-rw-r--r--src/org/apache/http/cookie/package.html41
-rw-r--r--src/org/apache/http/cookie/params/CookieSpecPNames.java68
-rw-r--r--src/org/apache/http/cookie/params/CookieSpecParamBean.java53
-rw-r--r--src/org/apache/http/cookie/params/package.html40
-rw-r--r--src/org/apache/http/entity/AbstractHttpEntity.java213
-rw-r--r--src/org/apache/http/entity/BasicHttpEntity.java146
-rw-r--r--src/org/apache/http/entity/BufferedHttpEntity.java120
-rw-r--r--src/org/apache/http/entity/ByteArrayEntity.java94
-rw-r--r--src/org/apache/http/entity/ContentLengthStrategy.java54
-rw-r--r--src/org/apache/http/entity/ContentProducer.java53
-rw-r--r--src/org/apache/http/entity/EntityTemplate.java86
-rw-r--r--src/org/apache/http/entity/FileEntity.java106
-rw-r--r--src/org/apache/http/entity/HttpEntityWrapper.java113
-rw-r--r--src/org/apache/http/entity/InputStreamEntity.java116
-rw-r--r--src/org/apache/http/entity/SerializableEntity.java107
-rw-r--r--src/org/apache/http/entity/StringEntity.java106
-rw-r--r--src/org/apache/http/entity/package.html58
-rw-r--r--src/org/apache/http/impl/AbstractHttpClientConnection.java212
-rw-r--r--src/org/apache/http/impl/AbstractHttpServerConnection.java202
-rw-r--r--src/org/apache/http/impl/DefaultConnectionReuseStrategy.java182
-rw-r--r--src/org/apache/http/impl/DefaultHttpClientConnection.java87
-rw-r--r--src/org/apache/http/impl/DefaultHttpRequestFactory.java113
-rw-r--r--src/org/apache/http/impl/DefaultHttpResponseFactory.java121
-rw-r--r--src/org/apache/http/impl/DefaultHttpServerConnection.java85
-rw-r--r--src/org/apache/http/impl/EnglishReasonPhraseCatalog.java234
-rw-r--r--src/org/apache/http/impl/HttpConnectionMetricsImpl.java146
-rw-r--r--src/org/apache/http/impl/NoConnectionReuseStrategy.java65
-rw-r--r--src/org/apache/http/impl/SocketHttpClientConnection.java208
-rw-r--r--src/org/apache/http/impl/SocketHttpServerConnection.java202
-rw-r--r--src/org/apache/http/impl/auth/AuthSchemeBase.java128
-rw-r--r--src/org/apache/http/impl/auth/BasicScheme.java185
-rw-r--r--src/org/apache/http/impl/auth/BasicSchemeFactory.java50
-rw-r--r--src/org/apache/http/impl/auth/DigestScheme.java484
-rw-r--r--src/org/apache/http/impl/auth/DigestSchemeFactory.java50
-rw-r--r--src/org/apache/http/impl/auth/NTLMEngine.java76
-rw-r--r--src/org/apache/http/impl/auth/NTLMEngineException.java70
-rw-r--r--src/org/apache/http/impl/auth/NTLMScheme.java149
-rw-r--r--src/org/apache/http/impl/auth/RFC2617Scheme.java119
-rw-r--r--src/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java71
-rw-r--r--src/org/apache/http/impl/auth/package.html4
-rw-r--r--src/org/apache/http/impl/client/AbstractAuthenticationHandler.java165
-rw-r--r--src/org/apache/http/impl/client/AbstractHttpClient.java697
-rw-r--r--src/org/apache/http/impl/client/BasicCookieStore.java162
-rw-r--r--src/org/apache/http/impl/client/BasicCredentialsProvider.java143
-rw-r--r--src/org/apache/http/impl/client/BasicResponseHandler.java79
-rw-r--r--src/org/apache/http/impl/client/ClientParamsStack.java282
-rw-r--r--src/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java76
-rw-r--r--src/org/apache/http/impl/client/DefaultHttpClient.java332
-rw-r--r--src/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java134
-rw-r--r--src/org/apache/http/impl/client/DefaultProxyAuthenticationHandler.java72
-rw-r--r--src/org/apache/http/impl/client/DefaultRedirectHandler.java183
-rw-r--r--src/org/apache/http/impl/client/DefaultRequestDirector.java1088
-rw-r--r--src/org/apache/http/impl/client/DefaultTargetAuthenticationHandler.java72
-rw-r--r--src/org/apache/http/impl/client/DefaultUserTokenHandler.java88
-rw-r--r--src/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java83
-rw-r--r--src/org/apache/http/impl/client/RedirectLocations.java71
-rw-r--r--src/org/apache/http/impl/client/RequestWrapper.java170
-rw-r--r--src/org/apache/http/impl/client/RoutedRequest.java73
-rw-r--r--src/org/apache/http/impl/client/TunnelRefusedException.java52
-rw-r--r--src/org/apache/http/impl/client/package.html4
-rw-r--r--src/org/apache/http/impl/conn/AbstractClientConnAdapter.java399
-rw-r--r--src/org/apache/http/impl/conn/AbstractPoolEntry.java322
-rw-r--r--src/org/apache/http/impl/conn/AbstractPooledConnAdapter.java188
-rw-r--r--src/org/apache/http/impl/conn/DefaultClientConnection.java259
-rw-r--r--src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java216
-rw-r--r--src/org/apache/http/impl/conn/DefaultHttpRoutePlanner.java121
-rw-r--r--src/org/apache/http/impl/conn/DefaultResponseParser.java103
-rw-r--r--src/org/apache/http/impl/conn/IdleConnectionHandler.java190
-rw-r--r--src/org/apache/http/impl/conn/LoggingSessionInputBuffer.java117
-rw-r--r--src/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java109
-rw-r--r--src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java290
-rw-r--r--src/org/apache/http/impl/conn/SingleClientConnManager.java444
-rw-r--r--src/org/apache/http/impl/conn/Wire.java160
-rw-r--r--src/org/apache/http/impl/conn/package.html5
-rw-r--r--src/org/apache/http/impl/conn/tsccm/AbstractConnPool.java332
-rw-r--r--src/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java88
-rw-r--r--src/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java80
-rw-r--r--src/org/apache/http/impl/conn/tsccm/BasicPooledConnAdapter.java83
-rw-r--r--src/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java698
-rw-r--r--src/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java68
-rw-r--r--src/org/apache/http/impl/conn/tsccm/RefQueueHandler.java48
-rw-r--r--src/org/apache/http/impl/conn/tsccm/RefQueueWorker.java139
-rw-r--r--src/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java301
-rw-r--r--src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java282
-rw-r--r--src/org/apache/http/impl/conn/tsccm/WaitingThread.java197
-rw-r--r--src/org/apache/http/impl/conn/tsccm/WaitingThreadAborter.java62
-rw-r--r--src/org/apache/http/impl/conn/tsccm/doc-files/tsccm-structure.pngbin0 -> 4224 bytes
-rw-r--r--src/org/apache/http/impl/conn/tsccm/package.html205
-rw-r--r--src/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java50
-rw-r--r--src/org/apache/http/impl/cookie/AbstractCookieSpec.java110
-rw-r--r--src/org/apache/http/impl/cookie/BasicClientCookie.java376
-rw-r--r--src/org/apache/http/impl/cookie/BasicClientCookie2.java101
-rw-r--r--src/org/apache/http/impl/cookie/BasicCommentHandler.java50
-rw-r--r--src/org/apache/http/impl/cookie/BasicDomainHandler.java122
-rw-r--r--src/org/apache/http/impl/cookie/BasicExpiresHandler.java65
-rw-r--r--src/org/apache/http/impl/cookie/BasicMaxAgeHandler.java66
-rw-r--r--src/org/apache/http/impl/cookie/BasicPathHandler.java91
-rw-r--r--src/org/apache/http/impl/cookie/BasicSecureHandler.java63
-rw-r--r--src/org/apache/http/impl/cookie/BestMatchSpec.java186
-rw-r--r--src/org/apache/http/impl/cookie/BestMatchSpecFactory.java57
-rw-r--r--src/org/apache/http/impl/cookie/BrowserCompatSpec.java188
-rw-r--r--src/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java56
-rw-r--r--src/org/apache/http/impl/cookie/CookieSpecBase.java131
-rw-r--r--src/org/apache/http/impl/cookie/DateParseException.java60
-rw-r--r--src/org/apache/http/impl/cookie/DateUtils.java261
-rw-r--r--src/org/apache/http/impl/cookie/NetscapeDomainHandler.java106
-rw-r--r--src/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java78
-rw-r--r--src/org/apache/http/impl/cookie/NetscapeDraftSpec.java182
-rw-r--r--src/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java56
-rw-r--r--src/org/apache/http/impl/cookie/RFC2109DomainHandler.java126
-rw-r--r--src/org/apache/http/impl/cookie/RFC2109Spec.java246
-rw-r--r--src/org/apache/http/impl/cookie/RFC2109SpecFactory.java57
-rw-r--r--src/org/apache/http/impl/cookie/RFC2109VersionHandler.java74
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java66
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java66
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java195
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java168
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965Spec.java259
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965SpecFactory.java57
-rw-r--r--src/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java96
-rw-r--r--src/org/apache/http/impl/cookie/package.html4
-rw-r--r--src/org/apache/http/impl/entity/EntityDeserializer.java115
-rw-r--r--src/org/apache/http/impl/entity/EntitySerializer.java101
-rw-r--r--src/org/apache/http/impl/entity/LaxContentLengthStrategy.java260
-rw-r--r--src/org/apache/http/impl/entity/StrictContentLengthStrategy.java220
-rw-r--r--src/org/apache/http/impl/entity/package.html41
-rw-r--r--src/org/apache/http/impl/io/AbstractMessageParser.java187
-rw-r--r--src/org/apache/http/impl/io/AbstractMessageWriter.java85
-rw-r--r--src/org/apache/http/impl/io/AbstractSessionInputBuffer.java271
-rw-r--r--src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java179
-rw-r--r--src/org/apache/http/impl/io/ChunkedInputStream.java294
-rw-r--r--src/org/apache/http/impl/io/ChunkedOutputStream.java191
-rw-r--r--src/org/apache/http/impl/io/ContentLengthInputStream.java220
-rw-r--r--src/org/apache/http/impl/io/ContentLengthOutputStream.java132
-rw-r--r--src/org/apache/http/impl/io/HttpRequestParser.java80
-rw-r--r--src/org/apache/http/impl/io/HttpRequestWriter.java59
-rw-r--r--src/org/apache/http/impl/io/HttpResponseParser.java81
-rw-r--r--src/org/apache/http/impl/io/HttpResponseWriter.java59
-rw-r--r--src/org/apache/http/impl/io/HttpTransportMetricsImpl.java63
-rw-r--r--src/org/apache/http/impl/io/IdentityInputStream.java90
-rw-r--r--src/org/apache/http/impl/io/IdentityOutputStream.java100
-rw-r--r--src/org/apache/http/impl/io/SocketInputBuffer.java115
-rw-r--r--src/org/apache/http/impl/io/SocketOutputBuffer.java79
-rw-r--r--src/org/apache/http/impl/io/package.html48
-rw-r--r--src/org/apache/http/impl/package.html41
-rw-r--r--src/org/apache/http/io/HttpMessageParser.java53
-rw-r--r--src/org/apache/http/io/HttpMessageWriter.java53
-rw-r--r--src/org/apache/http/io/HttpTransportMetrics.java46
-rw-r--r--src/org/apache/http/io/SessionInputBuffer.java63
-rw-r--r--src/org/apache/http/io/SessionOutputBuffer.java63
-rw-r--r--src/org/apache/http/io/package.html47
-rw-r--r--src/org/apache/http/message/AbstractHttpMessage.java166
-rw-r--r--src/org/apache/http/message/BasicHeader.java143
-rw-r--r--src/org/apache/http/message/BasicHeaderElement.java243
-rw-r--r--src/org/apache/http/message/BasicHeaderElementIterator.java161
-rw-r--r--src/org/apache/http/message/BasicHeaderIterator.java180
-rw-r--r--src/org/apache/http/message/BasicHeaderValueFormatter.java441
-rw-r--r--src/org/apache/http/message/BasicHeaderValueParser.java420
-rw-r--r--src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java81
-rw-r--r--src/org/apache/http/message/BasicHttpRequest.java98
-rw-r--r--src/org/apache/http/message/BasicHttpResponse.java204
-rw-r--r--src/org/apache/http/message/BasicLineFormatter.java346
-rw-r--r--src/org/apache/http/message/BasicLineParser.java504
-rw-r--r--src/org/apache/http/message/BasicListHeaderIterator.java196
-rw-r--r--src/org/apache/http/message/BasicNameValuePair.java189
-rw-r--r--src/org/apache/http/message/BasicRequestLine.java99
-rw-r--r--src/org/apache/http/message/BasicStatusLine.java124
-rw-r--r--src/org/apache/http/message/BasicTokenIterator.java429
-rw-r--r--src/org/apache/http/message/BufferedHeader.java133
-rw-r--r--src/org/apache/http/message/HeaderGroup.java295
-rw-r--r--src/org/apache/http/message/HeaderValueFormatter.java141
-rw-r--r--src/org/apache/http/message/HeaderValueParser.java214
-rw-r--r--src/org/apache/http/message/LineFormatter.java153
-rw-r--r--src/org/apache/http/message/LineParser.java156
-rw-r--r--src/org/apache/http/message/ParserCursor.java102
-rw-r--r--src/org/apache/http/message/package.html49
-rw-r--r--src/org/apache/http/package.html51
-rw-r--r--src/org/apache/http/params/AbstractHttpParams.java116
-rw-r--r--src/org/apache/http/params/BasicHttpParams.java160
-rw-r--r--src/org/apache/http/params/CoreConnectionPNames.java131
-rw-r--r--src/org/apache/http/params/CoreProtocolPNames.java132
-rw-r--r--src/org/apache/http/params/DefaultedHttpParams.java101
-rw-r--r--src/org/apache/http/params/HttpAbstractParamBean.java44
-rw-r--r--src/org/apache/http/params/HttpConnectionParamBean.java64
-rw-r--r--src/org/apache/http/params/HttpConnectionParams.java224
-rw-r--r--src/org/apache/http/params/HttpParams.java187
-rw-r--r--src/org/apache/http/params/HttpProtocolParamBean.java62
-rw-r--r--src/org/apache/http/params/HttpProtocolParams.java176
-rw-r--r--src/org/apache/http/params/package.html40
-rw-r--r--src/org/apache/http/protocol/BasicHttpContext.java95
-rw-r--r--src/org/apache/http/protocol/BasicHttpProcessor.java337
-rw-r--r--src/org/apache/http/protocol/DefaultedHttpContext.java79
-rw-r--r--src/org/apache/http/protocol/ExecutionContext.java52
-rw-r--r--src/org/apache/http/protocol/HTTP.java99
-rw-r--r--src/org/apache/http/protocol/HttpContext.java58
-rw-r--r--src/org/apache/http/protocol/HttpDateGenerator.java81
-rw-r--r--src/org/apache/http/protocol/HttpExpectationVerifier.java73
-rw-r--r--src/org/apache/http/protocol/HttpProcessor.java56
-rw-r--r--src/org/apache/http/protocol/HttpRequestExecutor.java322
-rw-r--r--src/org/apache/http/protocol/HttpRequestHandler.java53
-rw-r--r--src/org/apache/http/protocol/HttpRequestHandlerRegistry.java82
-rw-r--r--src/org/apache/http/protocol/HttpRequestHandlerResolver.java46
-rw-r--r--src/org/apache/http/protocol/HttpRequestInterceptorList.java120
-rw-r--r--src/org/apache/http/protocol/HttpResponseInterceptorList.java121
-rw-r--r--src/org/apache/http/protocol/HttpService.java249
-rw-r--r--src/org/apache/http/protocol/RequestConnControl.java67
-rw-r--r--src/org/apache/http/protocol/RequestContent.java101
-rw-r--r--src/org/apache/http/protocol/RequestDate.java72
-rw-r--r--src/org/apache/http/protocol/RequestExpectContinue.java78
-rw-r--r--src/org/apache/http/protocol/RequestTargetHost.java98
-rw-r--r--src/org/apache/http/protocol/RequestUserAgent.java69
-rw-r--r--src/org/apache/http/protocol/ResponseConnControl.java104
-rw-r--r--src/org/apache/http/protocol/ResponseContent.java101
-rw-r--r--src/org/apache/http/protocol/ResponseDate.java73
-rw-r--r--src/org/apache/http/protocol/ResponseServer.java71
-rw-r--r--src/org/apache/http/protocol/SyncBasicHttpContext.java61
-rw-r--r--src/org/apache/http/protocol/UriPatternMatcher.java127
-rw-r--r--src/org/apache/http/protocol/package.html112
-rw-r--r--src/org/apache/http/svn.info8
-rw-r--r--src/org/apache/http/util/ByteArrayBuffer.java162
-rw-r--r--src/org/apache/http/util/CharArrayBuffer.java264
-rw-r--r--src/org/apache/http/util/EncodingUtils.java185
-rw-r--r--src/org/apache/http/util/EntityUtils.java149
-rw-r--r--src/org/apache/http/util/ExceptionUtils.java85
-rw-r--r--src/org/apache/http/util/LangUtils.java88
-rw-r--r--src/org/apache/http/util/VersionInfo.java317
-rw-r--r--src/org/apache/http/util/package.html45
392 files changed, 50073 insertions, 0 deletions
diff --git a/src/org/apache/http/ConnectionClosedException.java b/src/org/apache/http/ConnectionClosedException.java
new file mode 100644
index 0000000..fa0e2db
--- /dev/null
+++ b/src/org/apache/http/ConnectionClosedException.java
@@ -0,0 +1,58 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/ConnectionClosedException.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+/**
+ * Indicates that a connection has been closed.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public class ConnectionClosedException extends IOException {
+
+ private static final long serialVersionUID = 617550366255636674L;
+
+ /**
+ * Creates a new ConnectionClosedException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public ConnectionClosedException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/ConnectionReuseStrategy.java b/src/org/apache/http/ConnectionReuseStrategy.java
new file mode 100644
index 0000000..635cc5c
--- /dev/null
+++ b/src/org/apache/http/ConnectionReuseStrategy.java
@@ -0,0 +1,75 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/ConnectionReuseStrategy.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Interface for deciding whether a connection should be kept alive.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public interface ConnectionReuseStrategy {
+
+ /**
+ * Decides whether a connection can be kept open after a request.
+ * If this method returns <code>false</code>, the caller MUST
+ * close the connection to correctly implement the HTTP protocol.
+ * If it returns <code>true</code>, the caller SHOULD attempt to
+ * keep the connection open for reuse with another request.
+ * <br/>
+ * One can use the HTTP context to retrieve additional objects that
+ * may be relevant for the keep-alive strategy: the actual HTTP
+ * connection, the original HTTP request, target host if known,
+ * number of times the connection has been reused already and so on.
+ * <br/>
+ * If the connection is already closed, <code>false</code> is returned.
+ * The stale connection check MUST NOT be triggered by a
+ * connection reuse strategy.
+ *
+ * @param response
+ * The last response received over that connection.
+ * @param context the context in which the connection is being
+ * used.
+ *
+ * @return <code>true</code> if the connection is allowed to be reused, or
+ * <code>false</code> if it MUST NOT be reused
+ */
+ boolean keepAlive(HttpResponse response, HttpContext context);
+
+}
diff --git a/src/org/apache/http/FormattedHeader.java b/src/org/apache/http/FormattedHeader.java
new file mode 100644
index 0000000..04ea279
--- /dev/null
+++ b/src/org/apache/http/FormattedHeader.java
@@ -0,0 +1,68 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/FormattedHeader.java $
+ * $Revision: 569781 $
+ * $Date: 2007-08-26 02:05:06 -0700 (Sun, 26 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * An HTTP header which is already formatted.
+ * For example when headers are received, the original formatting
+ * can be preserved. This allows for the header to be sent without
+ * another formatting step.
+ *
+ *
+ * @version $Revision: 569781 $
+ */
+public interface FormattedHeader extends Header {
+
+
+ /**
+ * Obtains the buffer with the formatted header.
+ * The returned buffer MUST NOT be modified.
+ *
+ * @return the formatted header, in a buffer that must not be modified
+ */
+ CharArrayBuffer getBuffer()
+ ;
+
+ /**
+ * Obtains the start of the header value in the {@link #getBuffer buffer}.
+ * By accessing the value in the buffer, creation of a temporary string
+ * can be avoided.
+ *
+ * @return index of the first character of the header value
+ * in the buffer returned by {@link #getBuffer getBuffer}.
+ */
+ int getValuePos()
+ ;
+
+}
diff --git a/src/org/apache/http/Header.java b/src/org/apache/http/Header.java
new file mode 100644
index 0000000..4e04bec
--- /dev/null
+++ b/src/org/apache/http/Header.java
@@ -0,0 +1,64 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/Header.java $
+ * $Revision: 569636 $
+ * $Date: 2007-08-25 00:34:47 -0700 (Sat, 25 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * Represents an HTTP header field.
+ *
+ * <p>The HTTP header fields follow the same generic format as
+ * that given in Section 3.1 of RFC 822. Each header field consists
+ * of a name followed by a colon (":") and the field value. Field names
+ * are case-insensitive. The field value MAY be preceded by any amount
+ * of LWS, though a single SP is preferred.
+ *
+ *<pre>
+ * message-header = field-name ":" [ field-value ]
+ * field-name = token
+ * field-value = *( field-content | LWS )
+ * field-content = &lt;the OCTETs making up the field-value
+ * and consisting of either *TEXT or combinations
+ * of token, separators, and quoted-string&gt;
+ *</pre>
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @version $Revision: 569636 $
+ */
+public interface Header {
+
+ String getName();
+
+ String getValue();
+
+ HeaderElement[] getElements() throws ParseException;
+
+}
diff --git a/src/org/apache/http/HeaderElement.java b/src/org/apache/http/HeaderElement.java
new file mode 100644
index 0000000..ddc4a9e
--- /dev/null
+++ b/src/org/apache/http/HeaderElement.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HeaderElement.java $
+ * $Revision: 569828 $
+ * $Date: 2007-08-26 08:49:38 -0700 (Sun, 26 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * One element of an HTTP {@link Header header} value.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 569828 $ $Date: 2007-08-26 08:49:38 -0700 (Sun, 26 Aug 2007) $
+ *
+ * @since 4.0
+ */
+public interface HeaderElement {
+
+ String getName();
+
+ String getValue();
+
+ NameValuePair[] getParameters();
+
+ NameValuePair getParameterByName(String name);
+
+ int getParameterCount();
+
+ NameValuePair getParameter(int index);
+}
+
diff --git a/src/org/apache/http/HeaderElementIterator.java b/src/org/apache/http/HeaderElementIterator.java
new file mode 100644
index 0000000..14137f0
--- /dev/null
+++ b/src/org/apache/http/HeaderElementIterator.java
@@ -0,0 +1,61 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HeaderElementIterator.java $
+ * $Revision: 584542 $
+ * $Date: 2007-10-14 06:29:34 -0700 (Sun, 14 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.util.Iterator;
+
+/**
+ * A type-safe iterator for {@link HeaderElement HeaderElement} objects.
+ *
+ * @version $Revision: 584542 $
+ */
+public interface HeaderElementIterator extends Iterator {
+
+ /**
+ * Indicates whether there is another header element in this
+ * iteration.
+ *
+ * @return <code>true</code> if there is another header element,
+ * <code>false</code> otherwise
+ */
+ boolean hasNext();
+
+ /**
+ * Obtains the next header element from this iteration.
+ * This method should only be called while {@link #hasNext hasNext}
+ * is true.
+ *
+ * @return the next header element in this iteration
+ */
+ HeaderElement nextElement();
+
+}
diff --git a/src/org/apache/http/HeaderIterator.java b/src/org/apache/http/HeaderIterator.java
new file mode 100644
index 0000000..688b611
--- /dev/null
+++ b/src/org/apache/http/HeaderIterator.java
@@ -0,0 +1,64 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HeaderIterator.java $
+ * $Revision: 581981 $
+ * $Date: 2007-10-04 11:26:26 -0700 (Thu, 04 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+
+import java.util.Iterator;
+
+
+/**
+ * A type-safe iterator for {@link Header Header} objects.
+ *
+ * @version $Revision: 581981 $
+ */
+public interface HeaderIterator extends Iterator {
+
+ /**
+ * Indicates whether there is another header in this iteration.
+ *
+ * @return <code>true</code> if there is another header,
+ * <code>false</code> otherwise
+ */
+ boolean hasNext()
+ ;
+
+
+ /**
+ * Obtains the next header from this iteration.
+ * This method should only be called while {@link #hasNext hasNext}
+ * is true.
+ *
+ * @return the next header in this iteration
+ */
+ Header nextHeader()
+ ;
+}
diff --git a/src/org/apache/http/HttpClientConnection.java b/src/org/apache/http/HttpClientConnection.java
new file mode 100644
index 0000000..a38c8f3
--- /dev/null
+++ b/src/org/apache/http/HttpClientConnection.java
@@ -0,0 +1,112 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpClientConnection.java $
+ * $Revision: 542199 $
+ * $Date: 2007-05-28 04:23:46 -0700 (Mon, 28 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+/**
+ * An HTTP connection for use on the client side.
+ * It is used for sending requests and receiving responses.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 542199 $
+ *
+ * @since 4.0
+ */
+public interface HttpClientConnection extends HttpConnection {
+
+ /**
+ * Checks if response data is available from the connection. May wait for
+ * the specified time until some data becomes available. Note that some
+ * implementations may completely ignore the timeout parameter.
+ *
+ * @param timeout the maximum time in milliseconds to wait for data
+ * @return true if data is available; false if there was no data available
+ * even after waiting for <code>timeout</code> milliseconds.
+ * @throws IOException if an error happens on the connection
+ */
+ boolean isResponseAvailable(int timeout)
+ throws IOException;
+
+ /**
+ * Sends the request line and all headers over the connection.
+ * @param request the request whose headers to send.
+ * @throws HttpException
+ * @throws IOException
+ */
+ void sendRequestHeader(HttpRequest request)
+ throws HttpException, IOException;
+
+ /**
+ * Sends the request entity over the connection.
+ * @param request the request whose entity to send.
+ * @throws HttpException
+ * @throws IOException
+ */
+ void sendRequestEntity(HttpEntityEnclosingRequest request)
+ throws HttpException, IOException;
+
+ /**
+ * Receives the request line and headers of the next response available from
+ * this connection. The caller should examine the HttpResponse object to
+ * find out if it should try to receive a response entity as well.
+ *
+ * @return a new HttpResponse object with status line and headers
+ * initialized.
+ * @throws HttpException
+ * @throws IOException
+ */
+ HttpResponse receiveResponseHeader()
+ throws HttpException, IOException;
+
+ /**
+ * Receives the next response entity available from this connection and
+ * attaches it to an existing HttpResponse object.
+ *
+ * @param response the response to attach the entity to
+ * @throws HttpException
+ * @throws IOException
+ */
+ void receiveResponseEntity(HttpResponse response)
+ throws HttpException, IOException;
+
+ /**
+ * Writes out all pending buffered data over the open connection.
+ *
+ * @throws IOException
+ */
+ void flush() throws IOException;
+
+}
diff --git a/src/org/apache/http/HttpConnection.java b/src/org/apache/http/HttpConnection.java
new file mode 100644
index 0000000..a3311f8
--- /dev/null
+++ b/src/org/apache/http/HttpConnection.java
@@ -0,0 +1,110 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpConnection.java $
+ * $Revision: 548031 $
+ * $Date: 2007-06-17 04:28:38 -0700 (Sun, 17 Jun 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+/**
+ * A generic HTTP connection, useful on client and server side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 548031 $
+ *
+ * @since 4.0
+ */
+public interface HttpConnection {
+
+ /**
+ * Closes this connection gracefully.
+ * This method will attempt to flush the transmitter's
+ * internal buffer prior to closing the underlying socket.
+ * This method MUST NOT be called from a different thread to force
+ * shutdown of the connection. Use {@link #shutdown shutdown} instead.
+ */
+ public void close() throws IOException;
+
+ /**
+ * Checks if this connection is open.
+ * @return true if it is open, false if it is closed.
+ */
+ public boolean isOpen();
+
+ /**
+ * Checks whether this connection has gone down.
+ * Network connections may get closed during some time of inactivity
+ * for several reasons. The next time a read is attempted on such a
+ * connection it will throw an IOException.
+ * This method tries to alleviate this inconvenience by trying to
+ * find out if a connection is still usable. Implementations may do
+ * that by attempting a read with a very small timeout. Thus this
+ * method may block for a small amount of time before returning a result.
+ * It is therefore an <i>expensive</i> operation.
+ *
+ * @return <code>true</code> if attempts to use this connection are
+ * likely to succeed, or <code>false</code> if they are likely
+ * to fail and this connection should be closed
+ */
+ public boolean isStale();
+
+ /**
+ * Sets the socket timeout value.
+ *
+ * @param timeout timeout value in milliseconds
+ */
+ void setSocketTimeout(int timeout);
+
+ /**
+ * Returns the socket timeout value.
+ *
+ * @return positive value in milliseconds if a timeout is set,
+ * <code>0</code> if timeout is disabled or <code>-1</code> if
+ * timeout is undefined.
+ */
+ int getSocketTimeout();
+
+ /**
+ * Force-closes this connection.
+ * This is the only method of a connection which may be called
+ * from a different thread to terminate the connection.
+ * This method will not attempt to flush the transmitter's
+ * internal buffer prior to closing the underlying socket.
+ */
+ public void shutdown() throws IOException;
+
+ /**
+ * Returns a collection of connection metrcis
+ * @return HttpConnectionMetrics
+ */
+ HttpConnectionMetrics getMetrics();
+
+}
diff --git a/src/org/apache/http/HttpConnectionMetrics.java b/src/org/apache/http/HttpConnectionMetrics.java
new file mode 100644
index 0000000..289dd46
--- /dev/null
+++ b/src/org/apache/http/HttpConnectionMetrics.java
@@ -0,0 +1,79 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpConnectionMetrics.java $
+ * $Revision: 548035 $
+ * $Date: 2007-06-17 05:17:03 -0700 (Sun, 17 Jun 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * The point of access to the statistics of an {@link HttpConnection}.
+ */
+public interface HttpConnectionMetrics {
+
+ /**
+ * Returns the number of requests transferred over the connection,
+ * 0 if not available.
+ */
+ long getRequestCount();
+
+ /**
+ * Returns the number of responses transferred over the connection,
+ * 0 if not available.
+ */
+ long getResponseCount();
+
+ /**
+ * Returns the number of bytes transferred over the connection,
+ * 0 if not available.
+ */
+ long getSentBytesCount();
+
+ /**
+ * Returns the number of bytes transferred over the connection,
+ * 0 if not available.
+ */
+ long getReceivedBytesCount();
+
+ /**
+ * Return the value for the specified metric.
+ *
+ *@param metricName the name of the metric to query.
+ *
+ *@return the object representing the metric requested,
+ * <code>null</code> if the metric cannot not found.
+ */
+ Object getMetric(String metricName);
+
+ /**
+ * Resets the counts
+ *
+ */
+ void reset();
+
+}
diff --git a/src/org/apache/http/HttpEntity.java b/src/org/apache/http/HttpEntity.java
new file mode 100644
index 0000000..51ddafc
--- /dev/null
+++ b/src/org/apache/http/HttpEntity.java
@@ -0,0 +1,196 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpEntity.java $
+ * $Revision: 645824 $
+ * $Date: 2008-04-08 03:12:41 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An entity that can be sent or received with an HTTP message.
+ * Entities can be found in some
+ * {@link HttpEntityEnclosingRequest requests} and in
+ * {@link HttpResponse responses}, where they are optional.
+ * <p>
+ * In some places, the JavaDoc distinguishes three kinds of entities,
+ * depending on where their {@link #getContent content} originates:
+ * <ul>
+ * <li><b>streamed</b>: The content is received from a stream, or
+ * generated on the fly. In particular, this category includes
+ * entities being received from a {@link HttpConnection connection}.
+ * {@link #isStreaming Streamed} entities are generally not
+ * {@link #isRepeatable repeatable}.
+ * </li>
+ * <li><b>self-contained</b>: The content is in memory or obtained by
+ * means that are independent from a connection or other entity.
+ * Self-contained entities are generally {@link #isRepeatable repeatable}.
+ * </li>
+ * <li><b>wrapping</b>: The content is obtained from another entity.
+ * </li>
+ * </ul>
+ * This distinction is important for connection management with incoming
+ * entities. For entities that are created by an application and only sent
+ * using the HTTP components framework, the difference between streamed
+ * and self-contained is of little importance. In that case, it is suggested
+ * to consider non-repeatable entities as streamed, and those that are
+ * repeatable (without a huge effort) as self-contained.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 645824 $
+ *
+ * @since 4.0
+ */
+public interface HttpEntity {
+
+ /**
+ * Tells if the entity is capable to produce its data more than once.
+ * A repeatable entity's getContent() and writeTo(OutputStream) methods
+ * can be called more than once whereas a non-repeatable entity's can not.
+ * @return true if the entity is repeatable, false otherwise.
+ */
+ boolean isRepeatable();
+
+ /**
+ * Tells about chunked encoding for this entity.
+ * The primary purpose of this method is to indicate whether
+ * chunked encoding should be used when the entity is sent.
+ * For entities that are received, it can also indicate whether
+ * the entity was received with chunked encoding.
+ * <br/>
+ * The behavior of wrapping entities is implementation dependent,
+ * but should respect the primary purpose.
+ *
+ * @return <code>true</code> if chunked encoding is preferred for this
+ * entity, or <code>false</code> if it is not
+ */
+ boolean isChunked();
+
+ /**
+ * Tells the length of the content, if known.
+ *
+ * @return the number of bytes of the content, or
+ * a negative number if unknown. If the content length is known
+ * but exceeds {@link java.lang.Long#MAX_VALUE Long.MAX_VALUE},
+ * a negative number is returned.
+ */
+ long getContentLength();
+
+ /**
+ * Obtains the Content-Type header, if known.
+ * This is the header that should be used when sending the entity,
+ * or the one that was received with the entity. It can include a
+ * charset attribute.
+ *
+ * @return the Content-Type header for this entity, or
+ * <code>null</code> if the content type is unknown
+ */
+ Header getContentType();
+
+ /**
+ * Obtains the Content-Encoding header, if known.
+ * This is the header that should be used when sending the entity,
+ * or the one that was received with the entity.
+ * Wrapping entities that modify the content encoding should
+ * adjust this header accordingly.
+ *
+ * @return the Content-Encoding header for this entity, or
+ * <code>null</code> if the content encoding is unknown
+ */
+ Header getContentEncoding();
+
+ /**
+ * Creates a new InputStream object of the entity.
+ * It is a programming error
+ * to return the same InputStream object more than once.
+ * Entities that are not {@link #isRepeatable repeatable}
+ * will throw an exception if this method is called multiple times.
+ *
+ * @return a new input stream that returns the entity data.
+ *
+ * @throws IOException if the stream could not be created
+ * @throws IllegalStateException
+ * if this entity is not repeatable and the stream
+ * has already been obtained previously
+ */
+ InputStream getContent() throws IOException, IllegalStateException;
+
+ /**
+ * Writes the entity content to the output stream.
+ *
+ * @param outstream the output stream to write entity content to
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ void writeTo(OutputStream outstream) throws IOException;
+
+ /**
+ * Tells whether this entity depends on an underlying stream.
+ * Streamed entities should return <code>true</code> until the
+ * content has been consumed, <code>false</code> afterwards.
+ * Self-contained entities should return <code>false</code>.
+ * Wrapping entities should delegate this call to the wrapped entity.
+ * <br/>
+ * The content of a streamed entity is consumed when the stream
+ * returned by {@link #getContent getContent} has been read to EOF,
+ * or after {@link #consumeContent consumeContent} has been called.
+ * If a streamed entity can not detect whether the stream has been
+ * read to EOF, it should return <code>true</code> until
+ * {@link #consumeContent consumeContent} is called.
+ *
+ * @return <code>true</code> if the entity content is streamed and
+ * not yet consumed, <code>false</code> otherwise
+ */
+ boolean isStreaming(); // don't expect an exception here
+
+ /**
+ * TODO: The name of this method is misnomer. It will be renamed to
+ * #finish() in the next major release.
+ * <br/>
+ * This method is called to indicate that the content of this entity
+ * is no longer required. All entity implementations are expected to
+ * release all allocated resources as a result of this method
+ * invocation. Content streaming entities are also expected to
+ * dispose of the remaining content, if any. Wrapping entities should
+ * delegate this call to the wrapped entity.
+ * <br/>
+ * This method is of particular importance for entities being
+ * received from a {@link HttpConnection connection}. The entity
+ * needs to be consumed completely in order to re-use the connection
+ * with keep-alive.
+ *
+ * @throws IOException if an I/O error occurs.
+ * This indicates that connection keep-alive is not possible.
+ */
+ void consumeContent() throws IOException;
+
+} // interface HttpEntity
diff --git a/src/org/apache/http/HttpEntityEnclosingRequest.java b/src/org/apache/http/HttpEntityEnclosingRequest.java
new file mode 100644
index 0000000..c47c32b
--- /dev/null
+++ b/src/org/apache/http/HttpEntityEnclosingRequest.java
@@ -0,0 +1,63 @@
+/*
+ * $Header: $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * A request with an entity.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public interface HttpEntityEnclosingRequest extends HttpRequest {
+
+ /**
+ * Tells if this request should use the expect-continue handshake.
+ * The expect continue handshake gives the server a chance to decide
+ * whether to accept the entity enclosing request before the possibly
+ * lengthy entity is sent across the wire.
+ * @return true if the expect continue handshake should be used, false if
+ * not.
+ */
+ boolean expectContinue();
+
+ /**
+ * Hands the entity to the request.
+ * @param entity the entity to send.
+ */
+ void setEntity(HttpEntity entity);
+
+ HttpEntity getEntity();
+
+}
diff --git a/src/org/apache/http/HttpException.java b/src/org/apache/http/HttpException.java
new file mode 100644
index 0000000..77aacb1
--- /dev/null
+++ b/src/org/apache/http/HttpException.java
@@ -0,0 +1,75 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpException.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import org.apache.http.util.ExceptionUtils;
+
+/**
+ * Signals that an HTTP exception has occurred.
+ *
+ * @author Laura Werner
+ *
+ * @version $Revision: 618017 $ $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ */
+public class HttpException extends Exception {
+
+ private static final long serialVersionUID = -5437299376222011036L;
+
+ /**
+ * Creates a new HttpException with a <tt>null</tt> detail message.
+ */
+ public HttpException() {
+ super();
+ }
+
+ /**
+ * Creates a new HttpException with the specified detail message.
+ *
+ * @param message the exception detail message
+ */
+ public HttpException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new HttpException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public HttpException(final String message, final Throwable cause) {
+ super(message);
+ ExceptionUtils.initCause(this, cause);
+ }
+
+}
diff --git a/src/org/apache/http/HttpHost.java b/src/org/apache/http/HttpHost.java
new file mode 100644
index 0000000..869f5af
--- /dev/null
+++ b/src/org/apache/http/HttpHost.java
@@ -0,0 +1,218 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpHost.java $
+ * $Revision: 653058 $
+ * $Date: 2008-05-03 05:01:10 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.util.Locale;
+
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.LangUtils;
+
+/**
+ * Holds all of the variables needed to describe an HTTP connection to a host.
+ * This includes remote host name, port and scheme.
+ *
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author Laura Werner
+ *
+ * @since 4.0
+ */
+public final class HttpHost implements Cloneable {
+
+ /** The default scheme is "http". */
+ public static final String DEFAULT_SCHEME_NAME = "http";
+
+ /** The host to use. */
+ protected final String hostname;
+
+ /** The lowercase host, for {@link #equals} and {@link #hashCode}. */
+ protected final String lcHostname;
+
+
+ /** The port to use. */
+ protected final int port;
+
+ /** The scheme */
+ protected final String schemeName;
+
+
+ /**
+ * Creates a new {@link HttpHost HttpHost}, specifying all values.
+ * Constructor for HttpHost.
+ *
+ * @param hostname the hostname (IP or DNS name)
+ * @param port the port number.
+ * <code>-1</code> indicates the scheme default port.
+ * @param scheme the name of the scheme.
+ * <code>null</code> indicates the
+ * {@link #DEFAULT_SCHEME_NAME default scheme}
+ */
+ public HttpHost(final String hostname, int port, final String scheme) {
+ super();
+ if (hostname == null) {
+ throw new IllegalArgumentException("Host name may not be null");
+ }
+ this.hostname = hostname;
+ this.lcHostname = hostname.toLowerCase(Locale.ENGLISH);
+ if (scheme != null) {
+ this.schemeName = scheme.toLowerCase(Locale.ENGLISH);
+ } else {
+ this.schemeName = DEFAULT_SCHEME_NAME;
+ }
+ this.port = port;
+ }
+
+ /**
+ * Creates a new {@link HttpHost HttpHost}, with default scheme.
+ *
+ * @param hostname the hostname (IP or DNS name)
+ * @param port the port number.
+ * <code>-1</code> indicates the scheme default port.
+ */
+ public HttpHost(final String hostname, int port) {
+ this(hostname, port, null);
+ }
+
+ /**
+ * Creates a new {@link HttpHost HttpHost}, with default scheme and port.
+ *
+ * @param hostname the hostname (IP or DNS name)
+ */
+ public HttpHost(final String hostname) {
+ this(hostname, -1, null);
+ }
+
+ /**
+ * Copy constructor for {@link HttpHost HttpHost}.
+ *
+ * @param httphost the HTTP host to copy details from
+ */
+ public HttpHost (final HttpHost httphost) {
+ this(httphost.hostname, httphost.port, httphost.schemeName);
+ }
+
+ /**
+ * Returns the host name.
+ *
+ * @return the host name (IP or DNS name)
+ */
+ public String getHostName() {
+ return this.hostname;
+ }
+
+ /**
+ * Returns the port.
+ *
+ * @return the host port, or <code>-1</code> if not set
+ */
+ public int getPort() {
+ return this.port;
+ }
+
+ /**
+ * Returns the scheme name.
+ *
+ * @return the scheme name
+ */
+ public String getSchemeName() {
+ return this.schemeName;
+ }
+
+ /**
+ * Return the host URI, as a string.
+ *
+ * @return the host URI
+ */
+ public String toURI() {
+ CharArrayBuffer buffer = new CharArrayBuffer(32);
+ buffer.append(this.schemeName);
+ buffer.append("://");
+ buffer.append(this.hostname);
+ if (this.port != -1) {
+ buffer.append(':');
+ buffer.append(Integer.toString(this.port));
+ }
+ return buffer.toString();
+ }
+
+
+ /**
+ * Obtains the host string, without scheme prefix.
+ *
+ * @return the host string, for example <code>localhost:8080</code>
+ */
+ public String toHostString() {
+ CharArrayBuffer buffer = new CharArrayBuffer(32);
+ buffer.append(this.hostname);
+ if (this.port != -1) {
+ buffer.append(':');
+ buffer.append(Integer.toString(this.port));
+ }
+ return buffer.toString();
+ }
+
+
+ public String toString() {
+ return toURI();
+ }
+
+
+ public boolean equals(final Object obj) {
+ if (obj == null) return false;
+ if (this == obj) return true;
+ if (obj instanceof HttpHost) {
+ HttpHost that = (HttpHost) obj;
+ return this.lcHostname.equals(that.lcHostname)
+ && this.port == that.port
+ && this.schemeName.equals(that.schemeName);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.lcHostname);
+ hash = LangUtils.hashCode(hash, this.port);
+ hash = LangUtils.hashCode(hash, this.schemeName);
+ return hash;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/HttpInetConnection.java b/src/org/apache/http/HttpInetConnection.java
new file mode 100644
index 0000000..32ac04a
--- /dev/null
+++ b/src/org/apache/http/HttpInetConnection.java
@@ -0,0 +1,55 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpInetConnection.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.net.InetAddress;
+
+/**
+ * An HTTP connection over the Internet Protocol (IP).
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 613298 $
+ *
+ * @since 4.0
+ */
+public interface HttpInetConnection extends HttpConnection {
+
+ InetAddress getLocalAddress();
+
+ int getLocalPort();
+
+ InetAddress getRemoteAddress();
+
+ int getRemotePort();
+
+}
diff --git a/src/org/apache/http/HttpMessage.java b/src/org/apache/http/HttpMessage.java
new file mode 100644
index 0000000..d24f0b4
--- /dev/null
+++ b/src/org/apache/http/HttpMessage.java
@@ -0,0 +1,191 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpMessage.java $
+ * $Revision: 610823 $
+ * $Date: 2008-01-10 07:53:53 -0800 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ * A generic HTTP message.
+ * Holds what is common between requests and responses.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 610823 $
+ *
+ * @since 4.0
+ */
+public interface HttpMessage {
+
+ /**
+ * Returns the protocol version this message is compatible with.
+ */
+ ProtocolVersion getProtocolVersion();
+
+ /**
+ * Checks if a certain header is present in this message. Header values are
+ * ignored.
+ *
+ * @param name the header name to check for.
+ * @return true if at least one header with this name is present.
+ */
+ boolean containsHeader(String name);
+
+ /**
+ * Returns all the headers with a specified name of this message. Header values
+ * are ignored. Headers are orderd in the sequence they will be sent over a
+ * connection.
+ *
+ * @param name the name of the headers to return.
+ * @return the headers whose name property equals <code>name</code>.
+ */
+ Header[] getHeaders(String name);
+
+ /**
+ * Returns the first header with a specified name of this message. Header
+ * values are ignored. If there is more than one matching header in the
+ * message the first element of {@link #getHeaders(String)} is returned.
+ * If there is no matching header in the message <code>null</code> is
+ * returned.
+ *
+ * @param name the name of the header to return.
+ * @return the first header whose name property equals <code>name</code>
+ * or <code>null</code> if no such header could be found.
+ */
+ Header getFirstHeader(String name);
+
+ /**
+ * Returns the last header with a specified name of this message. Header values
+ * are ignored. If there is more than one matching header in the message the
+ * last element of {@link #getHeaders(String)} is returned. If there is no
+ * matching header in the message <code>null</code> is returned.
+ *
+ * @param name the name of the header to return.
+ * @return the last header whose name property equals <code>name</code>.
+ * or <code>null</code> if no such header could be found.
+ */
+ Header getLastHeader(String name);
+
+ /**
+ * Returns all the headers of this message. Headers are orderd in the sequence
+ * they will be sent over a connection.
+ *
+ * @return all the headers of this message
+ */
+ Header[] getAllHeaders();
+
+ /**
+ * Adds a header to this message. The header will be appended to the end of
+ * the list.
+ *
+ * @param header the header to append.
+ */
+ void addHeader(Header header);
+
+ /**
+ * Adds a header to this message. The header will be appended to the end of
+ * the list.
+ *
+ * @param name the name of the header.
+ * @param value the value of the header.
+ */
+ void addHeader(String name, String value);
+
+ /**
+ * Overwrites the first header with the same name. The new header will be appended to
+ * the end of the list, if no header with the given name can be found.
+ *
+ * @param header the header to set.
+ */
+ void setHeader(Header header);
+
+ /**
+ * Overwrites the first header with the same name. The new header will be appended to
+ * the end of the list, if no header with the given name can be found.
+ *
+ * @param name the name of the header.
+ * @param value the value of the header.
+ */
+ void setHeader(String name, String value);
+
+ /**
+ * Overwrites all the headers in the message.
+ *
+ * @param headers the array of headers to set.
+ */
+ void setHeaders(Header[] headers);
+
+ /**
+ * Removes a header from this message.
+ *
+ * @param header the header to remove.
+ */
+ void removeHeader(Header header);
+
+ /**
+ * Removes all headers with a certain name from this message.
+ *
+ * @param name The name of the headers to remove.
+ */
+ void removeHeaders(String name);
+
+ /**
+ * Returns an iterator of all the headers.
+ *
+ * @return Iterator that returns Header objects in the sequence they are
+ * sent over a connection.
+ */
+ HeaderIterator headerIterator();
+
+ /**
+ * Returns an iterator of the headers with a given name.
+ *
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for all headers
+ *
+ * @return Iterator that returns Header objects with the argument name
+ * in the sequence they are sent over a connection.
+ */
+ HeaderIterator headerIterator(String name);
+
+ /**
+ * Returns the parameters effective for this message as set by
+ * {@link #setParams(HttpParams)}.
+ */
+ HttpParams getParams();
+
+ /**
+ * Provides parameters to be used for the processing of this message.
+ * @param params the parameters
+ */
+ void setParams(HttpParams params);
+
+}
diff --git a/src/org/apache/http/HttpRequest.java b/src/org/apache/http/HttpRequest.java
new file mode 100644
index 0000000..8558a97
--- /dev/null
+++ b/src/org/apache/http/HttpRequest.java
@@ -0,0 +1,51 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpRequest.java $
+ * $Revision: 528428 $
+ * $Date: 2007-04-13 03:26:04 -0700 (Fri, 13 Apr 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * An HTTP request.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 528428 $
+ *
+ * @since 4.0
+ */
+public interface HttpRequest extends HttpMessage {
+
+ /**
+ * Returns the request line of this request.
+ * @return the request line.
+ */
+ RequestLine getRequestLine();
+
+}
diff --git a/src/org/apache/http/HttpRequestFactory.java b/src/org/apache/http/HttpRequestFactory.java
new file mode 100644
index 0000000..d385127
--- /dev/null
+++ b/src/org/apache/http/HttpRequestFactory.java
@@ -0,0 +1,51 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpRequestFactory.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * A factory for {@link HttpRequest HttpRequest} objects.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public interface HttpRequestFactory {
+
+ HttpRequest newHttpRequest(RequestLine requestline)
+ throws MethodNotSupportedException;
+
+ HttpRequest newHttpRequest(String method, String uri)
+ throws MethodNotSupportedException;
+
+}
diff --git a/src/org/apache/http/HttpRequestInterceptor.java b/src/org/apache/http/HttpRequestInterceptor.java
new file mode 100644
index 0000000..db2194f
--- /dev/null
+++ b/src/org/apache/http/HttpRequestInterceptor.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpRequestInterceptor.java $
+ * $Revision: 618367 $
+ * $Date: 2008-02-04 10:26:06 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+import org.apache.http.protocol.HttpContext;
+
+
+/**
+ * Processes a request.
+ * Provides the ability to process a request before it is sent
+ * to the server or after it has received on the server side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 618367 $
+ *
+ * @since 4.0
+ */
+public interface HttpRequestInterceptor {
+
+ /**
+ * Processes a request.
+ * On the client side, this step is performed before the request is
+ * sent to the server. On the server side, this step is performed
+ * on incoming messages before the message body is evaluated.
+ *
+ * @param request the request to preprocess
+ * @param context the context for the request
+ *
+ * @throws IOException in case of an IO problem
+ * @throws HttpException in case of a protocol or other problem
+ */
+ void process(HttpRequest request, HttpContext context)
+ throws HttpException, IOException;
+
+}
diff --git a/src/org/apache/http/HttpResponse.java b/src/org/apache/http/HttpResponse.java
new file mode 100644
index 0000000..f232f86
--- /dev/null
+++ b/src/org/apache/http/HttpResponse.java
@@ -0,0 +1,161 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpResponse.java $
+ * $Revision: 652956 $
+ * $Date: 2008-05-02 17:13:05 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+
+import java.util.Locale;
+
+
+/**
+ * An HTTP response.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 652956 $
+ *
+ * @since 4.0
+ */
+public interface HttpResponse extends HttpMessage {
+
+ /**
+ * Obtains the status line of this response.
+ * The status line can be set using one of the
+ * {@link #setStatusLine setStatusLine} methods,
+ * or it can be initialized in a constructor.
+ *
+ * @return the status line, or <code>null</code> if not yet set
+ */
+ StatusLine getStatusLine();
+
+ /**
+ * Sets the status line of this response.
+ *
+ * @param statusline the status line of this response
+ */
+ void setStatusLine(StatusLine statusline);
+
+ /**
+ * Sets the status line of this response.
+ * The reason phrase will be determined based on the current
+ * {@link #getLocale locale}.
+ *
+ * @param ver the HTTP version
+ * @param code the status code
+ */
+ void setStatusLine(ProtocolVersion ver, int code);
+
+ /**
+ * Sets the status line of this response with a reason phrase.
+ *
+ * @param ver the HTTP version
+ * @param code the status code
+ * @param reason the reason phrase, or <code>null</code> to omit
+ */
+ void setStatusLine(ProtocolVersion ver, int code, String reason);
+
+ /**
+ * Updates the status line of this response with a new status code.
+ * The status line can only be updated if it is available. It must
+ * have been set either explicitly or in a constructor.
+ * <br/>
+ * The reason phrase will be updated according to the new status code,
+ * based on the current {@link #getLocale locale}. It can be set
+ * explicitly using {@link #setReasonPhrase setReasonPhrase}.
+ *
+ * @param code the HTTP status code.
+ *
+ * @throws IllegalStateException
+ * if the status line has not be set
+ *
+ * @see HttpStatus
+ * @see #setStatusLine(StatusLine)
+ * @see #setStatusLine(ProtocolVersion,int)
+ */
+ void setStatusCode(int code)
+ throws IllegalStateException;
+
+ /**
+ * Updates the status line of this response with a new reason phrase.
+ * The status line can only be updated if it is available. It must
+ * have been set either explicitly or in a constructor.
+ *
+ * @param reason the new reason phrase as a single-line string, or
+ * <code>null</code> to unset the reason phrase
+ *
+ * @throws IllegalStateException
+ * if the status line has not be set
+ *
+ * @see #setStatusLine(StatusLine)
+ * @see #setStatusLine(ProtocolVersion,int)
+ */
+ void setReasonPhrase(String reason)
+ throws IllegalStateException;
+
+ /**
+ * Obtains the message entity of this response, if any.
+ * The entity is provided by calling {@link #setEntity setEntity}.
+ *
+ * @return the response entity, or
+ * <code>null</code> if there is none
+ */
+ HttpEntity getEntity();
+
+ /**
+ * Associates a response entity with this response.
+ *
+ * @param entity the entity to associate with this response, or
+ * <code>null</code> to unset
+ */
+ void setEntity(HttpEntity entity);
+
+ /**
+ * Obtains the locale of this response.
+ * The locale is used to determine the reason phrase
+ * for the {@link #setStatusCode status code}.
+ * It can be changed using {@link #setLocale setLocale}.
+ *
+ * @return the locale of this response, never <code>null</code>
+ */
+ Locale getLocale();
+
+ /**
+ * Changes the locale of this response.
+ * If there is a status line, it's reason phrase will be updated
+ * according to the status code and new locale.
+ *
+ * @param loc the new locale
+ *
+ * @see #getLocale getLocale
+ * @see #setStatusCode setStatusCode
+ */
+ void setLocale(Locale loc);
+}
diff --git a/src/org/apache/http/HttpResponseFactory.java b/src/org/apache/http/HttpResponseFactory.java
new file mode 100644
index 0000000..3ed06ff
--- /dev/null
+++ b/src/org/apache/http/HttpResponseFactory.java
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpResponseFactory.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import org.apache.http.protocol.HttpContext;
+
+
+/**
+ * A factory for {@link HttpResponse HttpResponse} objects.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public interface HttpResponseFactory {
+
+ /**
+ * Creates a new response from status line elements.
+ *
+ * @param ver the protocol version
+ * @param status the status code
+ * @param context the context from which to determine the locale
+ * for looking up a reason phrase to the status code, or
+ * <code>null</code> to use the default locale
+ *
+ * @return the new response with an initialized status line
+ */
+ HttpResponse newHttpResponse(ProtocolVersion ver, int status,
+ HttpContext context);
+
+ /**
+ * Creates a new response from a status line.
+ *
+ * @param statusline the status line
+ * @param context the context from which to determine the locale
+ * for looking up a reason phrase if the status code
+ * is updated, or
+ * <code>null</code> to use the default locale
+ *
+ * @return the new response with the argument status line
+ */
+ HttpResponse newHttpResponse(StatusLine statusline,
+ HttpContext context);
+
+}
diff --git a/src/org/apache/http/HttpResponseInterceptor.java b/src/org/apache/http/HttpResponseInterceptor.java
new file mode 100644
index 0000000..cae1526
--- /dev/null
+++ b/src/org/apache/http/HttpResponseInterceptor.java
@@ -0,0 +1,68 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpResponseInterceptor.java $
+ * $Revision: 618367 $
+ * $Date: 2008-02-04 10:26:06 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Processes a response.
+ * Provides the ability to process a response before it is sent
+ * to the client or after it has been received on the client side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 618367 $
+ *
+ * @since 4.0
+ */
+public interface HttpResponseInterceptor {
+
+ /**
+ * Processes a response.
+ * On the server side, this step is performed before the response is
+ * sent to the client. On the client side, this step is performed
+ * on incoming messages before the message body is evaluated.
+ *
+ * @param response the response to postprocess
+ * @param context the context for the request
+ *
+ * @throws IOException in case of an IO problem
+ * @throws HttpException in case of a protocol or other problem
+ */
+ void process(HttpResponse response, HttpContext context)
+ throws HttpException, IOException;
+
+}
diff --git a/src/org/apache/http/HttpServerConnection.java b/src/org/apache/http/HttpServerConnection.java
new file mode 100644
index 0000000..8cea544
--- /dev/null
+++ b/src/org/apache/http/HttpServerConnection.java
@@ -0,0 +1,96 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpServerConnection.java $
+ * $Revision: 542199 $
+ * $Date: 2007-05-28 04:23:46 -0700 (Mon, 28 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+/**
+ * An HTTP connection for use on the server side.
+ * Requests are received, responses are sent.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 542199 $
+ *
+ * @since 4.0
+ */
+public interface HttpServerConnection extends HttpConnection {
+
+ /**
+ * Receives the request line and all headers available from this connection.
+ * The caller should examine the returned request and decide if to receive a
+ * request entity as well.
+ *
+ * @return a new HttpRequest object whose request line and headers are
+ * initialized.
+ * @throws HttpException
+ * @throws IOException
+ */
+ HttpRequest receiveRequestHeader()
+ throws HttpException, IOException;
+
+ /**
+ * Receives the next request entity available from this connection and attaches it to
+ * an existing request.
+ * @param request the request to attach the entity to.
+ * @throws HttpException
+ * @throws IOException
+ */
+ void receiveRequestEntity(HttpEntityEnclosingRequest request)
+ throws HttpException, IOException;
+
+ /**
+ * Sends the response line and headers of a response over this connection.
+ * @param response the response whose headers to send.
+ * @throws HttpException
+ * @throws IOException
+ */
+ void sendResponseHeader(HttpResponse response)
+ throws HttpException, IOException;
+
+ /**
+ * Sends the response entity of a response over this connection.
+ * @param response the response whose entity to send.
+ * @throws HttpException
+ * @throws IOException
+ */
+ void sendResponseEntity(HttpResponse response)
+ throws HttpException, IOException;
+
+ /**
+ * Sends all pending buffered data over this connection.
+ * @throws IOException
+ */
+ void flush()
+ throws IOException;
+
+}
diff --git a/src/org/apache/http/HttpStatus.java b/src/org/apache/http/HttpStatus.java
new file mode 100644
index 0000000..f8f7f5d
--- /dev/null
+++ b/src/org/apache/http/HttpStatus.java
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpStatus.java $
+ * $Revision: 503381 $
+ * $Date: 2007-02-04 02:59:10 -0800 (Sun, 04 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * Constants enumerating the HTTP status codes.
+ * All status codes defined in RFC1945 (HTTP/1.0), RFC2616 (HTTP/1.1), and
+ * RFC2518 (WebDAV) are listed.
+ *
+ * @see StatusLine
+ * @author Unascribed
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ *
+ * @version $Revision: 503381 $
+ */
+public interface HttpStatus {
+
+ // --- 1xx Informational ---
+
+ /** <tt>100 Continue</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_CONTINUE = 100;
+ /** <tt>101 Switching Protocols</tt> (HTTP/1.1 - RFC 2616)*/
+ public static final int SC_SWITCHING_PROTOCOLS = 101;
+ /** <tt>102 Processing</tt> (WebDAV - RFC 2518) */
+ public static final int SC_PROCESSING = 102;
+
+ // --- 2xx Success ---
+
+ /** <tt>200 OK</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_OK = 200;
+ /** <tt>201 Created</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_CREATED = 201;
+ /** <tt>202 Accepted</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_ACCEPTED = 202;
+ /** <tt>203 Non Authoritative Information</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
+ /** <tt>204 No Content</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_NO_CONTENT = 204;
+ /** <tt>205 Reset Content</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_RESET_CONTENT = 205;
+ /** <tt>206 Partial Content</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_PARTIAL_CONTENT = 206;
+ /**
+ * <tt>207 Multi-Status</tt> (WebDAV - RFC 2518) or <tt>207 Partial Update
+ * OK</tt> (HTTP/1.1 - draft-ietf-http-v11-spec-rev-01?)
+ */
+ public static final int SC_MULTI_STATUS = 207;
+
+ // --- 3xx Redirection ---
+
+ /** <tt>300 Mutliple Choices</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_MULTIPLE_CHOICES = 300;
+ /** <tt>301 Moved Permanently</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_MOVED_PERMANENTLY = 301;
+ /** <tt>302 Moved Temporarily</tt> (Sometimes <tt>Found</tt>) (HTTP/1.0 - RFC 1945) */
+ public static final int SC_MOVED_TEMPORARILY = 302;
+ /** <tt>303 See Other</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_SEE_OTHER = 303;
+ /** <tt>304 Not Modified</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_NOT_MODIFIED = 304;
+ /** <tt>305 Use Proxy</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_USE_PROXY = 305;
+ /** <tt>307 Temporary Redirect</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_TEMPORARY_REDIRECT = 307;
+
+ // --- 4xx Client Error ---
+
+ /** <tt>400 Bad Request</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_BAD_REQUEST = 400;
+ /** <tt>401 Unauthorized</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_UNAUTHORIZED = 401;
+ /** <tt>402 Payment Required</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_PAYMENT_REQUIRED = 402;
+ /** <tt>403 Forbidden</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_FORBIDDEN = 403;
+ /** <tt>404 Not Found</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_NOT_FOUND = 404;
+ /** <tt>405 Method Not Allowed</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_METHOD_NOT_ALLOWED = 405;
+ /** <tt>406 Not Acceptable</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_NOT_ACCEPTABLE = 406;
+ /** <tt>407 Proxy Authentication Required</tt> (HTTP/1.1 - RFC 2616)*/
+ public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
+ /** <tt>408 Request Timeout</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_REQUEST_TIMEOUT = 408;
+ /** <tt>409 Conflict</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_CONFLICT = 409;
+ /** <tt>410 Gone</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_GONE = 410;
+ /** <tt>411 Length Required</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_LENGTH_REQUIRED = 411;
+ /** <tt>412 Precondition Failed</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_PRECONDITION_FAILED = 412;
+ /** <tt>413 Request Entity Too Large</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_REQUEST_TOO_LONG = 413;
+ /** <tt>414 Request-URI Too Long</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_REQUEST_URI_TOO_LONG = 414;
+ /** <tt>415 Unsupported Media Type</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
+ /** <tt>416 Requested Range Not Satisfiable</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+ /** <tt>417 Expectation Failed</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_EXPECTATION_FAILED = 417;
+
+ /**
+ * Static constant for a 418 error.
+ * <tt>418 Unprocessable Entity</tt> (WebDAV drafts?)
+ * or <tt>418 Reauthentication Required</tt> (HTTP/1.1 drafts?)
+ */
+ // not used
+ // public static final int SC_UNPROCESSABLE_ENTITY = 418;
+
+ /**
+ * Static constant for a 419 error.
+ * <tt>419 Insufficient Space on Resource</tt>
+ * (WebDAV - draft-ietf-webdav-protocol-05?)
+ * or <tt>419 Proxy Reauthentication Required</tt>
+ * (HTTP/1.1 drafts?)
+ */
+ public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
+ /**
+ * Static constant for a 420 error.
+ * <tt>420 Method Failure</tt>
+ * (WebDAV - draft-ietf-webdav-protocol-05?)
+ */
+ public static final int SC_METHOD_FAILURE = 420;
+ /** <tt>422 Unprocessable Entity</tt> (WebDAV - RFC 2518) */
+ public static final int SC_UNPROCESSABLE_ENTITY = 422;
+ /** <tt>423 Locked</tt> (WebDAV - RFC 2518) */
+ public static final int SC_LOCKED = 423;
+ /** <tt>424 Failed Dependency</tt> (WebDAV - RFC 2518) */
+ public static final int SC_FAILED_DEPENDENCY = 424;
+
+ // --- 5xx Server Error ---
+
+ /** <tt>500 Server Error</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_INTERNAL_SERVER_ERROR = 500;
+ /** <tt>501 Not Implemented</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_NOT_IMPLEMENTED = 501;
+ /** <tt>502 Bad Gateway</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_BAD_GATEWAY = 502;
+ /** <tt>503 Service Unavailable</tt> (HTTP/1.0 - RFC 1945) */
+ public static final int SC_SERVICE_UNAVAILABLE = 503;
+ /** <tt>504 Gateway Timeout</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_GATEWAY_TIMEOUT = 504;
+ /** <tt>505 HTTP Version Not Supported</tt> (HTTP/1.1 - RFC 2616) */
+ public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
+
+ /** <tt>507 Insufficient Storage</tt> (WebDAV - RFC 2518) */
+ public static final int SC_INSUFFICIENT_STORAGE = 507;
+
+}
diff --git a/src/org/apache/http/HttpVersion.java b/src/org/apache/http/HttpVersion.java
new file mode 100644
index 0000000..243f199
--- /dev/null
+++ b/src/org/apache/http/HttpVersion.java
@@ -0,0 +1,104 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HttpVersion.java $
+ * $Revision: 609106 $
+ * $Date: 2008-01-05 01:15:42 -0800 (Sat, 05 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.Serializable;
+
+/**
+ * Represents an HTTP version, as specified in RFC 2616.
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 609106 $ $Date: 2008-01-05 01:15:42 -0800 (Sat, 05 Jan 2008) $
+ */
+public final class HttpVersion extends ProtocolVersion
+ implements Serializable {
+
+ private static final long serialVersionUID = -5856653513894415344L;
+
+ /** The protocol name. */
+ public static final String HTTP = "HTTP";
+
+ /** HTTP protocol version 0.9 */
+ public static final HttpVersion HTTP_0_9 = new HttpVersion(0, 9);
+
+ /** HTTP protocol version 1.0 */
+ public static final HttpVersion HTTP_1_0 = new HttpVersion(1, 0);
+
+ /** HTTP protocol version 1.1 */
+ public static final HttpVersion HTTP_1_1 = new HttpVersion(1, 1);
+
+
+ /**
+ * Create an HTTP protocol version designator.
+ *
+ * @param major the major version number of the HTTP protocol
+ * @param minor the minor version number of the HTTP protocol
+ *
+ * @throws IllegalArgumentException if either major or minor version number is negative
+ */
+ public HttpVersion(int major, int minor) {
+ super(HTTP, major, minor);
+ }
+
+
+ /**
+ * Obtains a specific HTTP version.
+ *
+ * @param major the major version
+ * @param minor the minor version
+ *
+ * @return an instance of {@link HttpVersion} with the argument version
+ */
+ public ProtocolVersion forVersion(int major, int minor) {
+
+ if ((major == this.major) && (minor == this.minor)) {
+ return this;
+ }
+
+ if (major == 1) {
+ if (minor == 0) {
+ return HTTP_1_0;
+ }
+ if (minor == 1) {
+ return HTTP_1_1;
+ }
+ }
+ if ((major == 0) && (minor == 9)) {
+ return HTTP_0_9;
+ }
+
+ // argument checking is done in the constructor
+ return new HttpVersion(major, minor);
+ }
+
+}
diff --git a/src/org/apache/http/MalformedChunkCodingException.java b/src/org/apache/http/MalformedChunkCodingException.java
new file mode 100644
index 0000000..2267a2e
--- /dev/null
+++ b/src/org/apache/http/MalformedChunkCodingException.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/MalformedChunkCodingException.java $
+ * $Revision: 609106 $
+ * $Date: 2008-01-05 01:15:42 -0800 (Sat, 05 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+/**
+ * Signals a malformed chunked stream.
+ */
+public class MalformedChunkCodingException extends IOException {
+
+ private static final long serialVersionUID = 2158560246948994524L;
+
+ /**
+ * Creates a MalformedChunkCodingException without a detail message.
+ */
+ public MalformedChunkCodingException() {
+ super();
+ }
+
+ /**
+ * Creates a MalformedChunkCodingException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public MalformedChunkCodingException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/MethodNotSupportedException.java b/src/org/apache/http/MethodNotSupportedException.java
new file mode 100644
index 0000000..3ccf72d
--- /dev/null
+++ b/src/org/apache/http/MethodNotSupportedException.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/MethodNotSupportedException.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+
+/**
+ * Indicates that an HTTP method is not supported.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public class MethodNotSupportedException extends HttpException {
+
+ private static final long serialVersionUID = 3365359036840171201L;
+
+ /**
+ * Creates a new MethodNotSupportedException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public MethodNotSupportedException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new MethodNotSupportedException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public MethodNotSupportedException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/NameValuePair.java b/src/org/apache/http/NameValuePair.java
new file mode 100644
index 0000000..1ab861a
--- /dev/null
+++ b/src/org/apache/http/NameValuePair.java
@@ -0,0 +1,108 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/NameValuePair.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * A simple class encapsulating an attribute/value pair.
+ * <p>
+ * This class comforms to the generic grammar and formatting rules outlined in the
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2">Section 2.2</a>
+ * and
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>
+ * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
+ * </p>
+ * <h>2.2 Basic Rules</h>
+ * <p>
+ * The following rules are used throughout this specification to describe basic parsing constructs.
+ * The US-ASCII coded character set is defined by ANSI X3.4-1986.
+ * </p>
+ * <pre>
+ * OCTET = <any 8-bit sequence of data>
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ * LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ * ALPHA = UPALPHA | LOALPHA
+ * DIGIT = <any US-ASCII digit "0".."9">
+ * CTL = <any US-ASCII control character
+ * (octets 0 - 31) and DEL (127)>
+ * CR = <US-ASCII CR, carriage return (13)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * <"> = <US-ASCII double-quote mark (34)>
+ * </pre>
+ * <p>
+ * Many HTTP/1.1 header field values consist of words separated by LWS or special
+ * characters. These special characters MUST be in a quoted string to be used within
+ * a parameter value (as defined in section 3.6).
+ * <p>
+ * <pre>
+ * token = 1*<any CHAR except CTLs or separators>
+ * separators = "(" | ")" | "<" | ">" | "@"
+ * | "," | ";" | ":" | "\" | <">
+ * | "/" | "[" | "]" | "?" | "="
+ * | "{" | "}" | SP | HT
+ * </pre>
+ * <p>
+ * A string of text is parsed as a single word if it is quoted using double-quote marks.
+ * </p>
+ * <pre>
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext = <any TEXT except <">>
+ * </pre>
+ * <p>
+ * The backslash character ("\") MAY be used as a single-character quoting mechanism only
+ * within quoted-string and comment constructs.
+ * </p>
+ * <pre>
+ * quoted-pair = "\" CHAR
+ * </pre>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ *
+ */
+public interface NameValuePair {
+
+ String getName();
+
+ String getValue();
+
+}
diff --git a/src/org/apache/http/NoHttpResponseException.java b/src/org/apache/http/NoHttpResponseException.java
new file mode 100644
index 0000000..a02ef5a
--- /dev/null
+++ b/src/org/apache/http/NoHttpResponseException.java
@@ -0,0 +1,58 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/NoHttpResponseException.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.IOException;
+
+/**
+ * <p>
+ * Signals that the target server failed to respond with a valid HTTP response.
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ */
+public class NoHttpResponseException extends IOException {
+
+ private static final long serialVersionUID = -7658940387386078766L;
+
+ /**
+ * Creates a new NoHttpResponseException with the specified detail message.
+ *
+ * @param message exception message
+ */
+ public NoHttpResponseException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/ParseException.java b/src/org/apache/http/ParseException.java
new file mode 100644
index 0000000..97083b2
--- /dev/null
+++ b/src/org/apache/http/ParseException.java
@@ -0,0 +1,65 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/ParseException.java $
+ * $Revision: 609106 $
+ * $Date: 2008-01-05 01:15:42 -0800 (Sat, 05 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * Indicates a parse error.
+ * Parse errors when receiving a message will typically trigger
+ * {@link ProtocolException}. Parse errors that do not occur during
+ * protocol execution may be handled differently.
+ * This is an unchecked exceptions, since there are cases where
+ * the data to be parsed has been generated and is therefore
+ * known to be parseable.
+ *
+ * @since 4.0
+ */
+public class ParseException extends RuntimeException {
+
+ private static final long serialVersionUID = -7288819855864183578L;
+
+ /**
+ * Creates a {@link ParseException} without details.
+ */
+ public ParseException() {
+ super();
+ }
+
+ /**
+ * Creates a {@link ParseException} with a detail message.
+ *
+ * @param message the exception detail message, or <code>null</code>
+ */
+ public ParseException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/ProtocolException.java b/src/org/apache/http/ProtocolException.java
new file mode 100644
index 0000000..b4c34ee
--- /dev/null
+++ b/src/org/apache/http/ProtocolException.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/ProtocolException.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * Signals that an HTTP protocol violation has occurred.
+ * For example a malformed status line or headers, a missing message body, etc.
+ *
+ * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
+ *
+ * @since 4.0
+ */
+public class ProtocolException extends HttpException {
+
+ private static final long serialVersionUID = -2143571074341228994L;
+
+ /**
+ * Creates a new ProtocolException with a <tt>null</tt> detail message.
+ */
+ public ProtocolException() {
+ super();
+ }
+
+ /**
+ * Creates a new ProtocolException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public ProtocolException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new ProtocolException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public ProtocolException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/ProtocolVersion.java b/src/org/apache/http/ProtocolVersion.java
new file mode 100644
index 0000000..ced76a5
--- /dev/null
+++ b/src/org/apache/http/ProtocolVersion.java
@@ -0,0 +1,287 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/ProtocolVersion.java $
+ * $Revision: 609106 $
+ * $Date: 2008-01-05 01:15:42 -0800 (Sat, 05 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.io.Serializable;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Represents a protocol version, as specified in RFC 2616.
+ * RFC 2616 specifies only HTTP versions, like "HTTP/1.1" and "HTTP/1.0".
+ * RFC 3261 specifies a message format that is identical to HTTP except
+ * for the protocol name. It defines a protocol version "SIP/2.0".
+ * There are some nitty-gritty differences between the interpretation
+ * of versions in HTTP and SIP. In those cases, HTTP takes precedence.
+ * <p>
+ * This class defines a protocol version as a combination of
+ * protocol name, major version number, and minor version number.
+ * Note that {@link #equals} and {@link #hashCode} are defined as
+ * final here, they cannot be overridden in derived classes.
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 609106 $
+ */
+public class ProtocolVersion implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = 8950662842175091068L;
+
+
+ /** Name of the protocol. */
+ protected final String protocol;
+
+ /** Major version number of the protocol */
+ protected final int major;
+
+ /** Minor version number of the protocol */
+ protected final int minor;
+
+
+ /**
+ * Create a protocol version designator.
+ *
+ * @param protocol the name of the protocol, for example "HTTP"
+ * @param major the major version number of the protocol
+ * @param minor the minor version number of the protocol
+ */
+ public ProtocolVersion(String protocol, int major, int minor) {
+ if (protocol == null) {
+ throw new IllegalArgumentException
+ ("Protocol name must not be null.");
+ }
+ if (major < 0) {
+ throw new IllegalArgumentException
+ ("Protocol major version number must not be negative.");
+ }
+ if (minor < 0) {
+ throw new IllegalArgumentException
+ ("Protocol minor version number may not be negative");
+ }
+ this.protocol = protocol;
+ this.major = major;
+ this.minor = minor;
+ }
+
+ /**
+ * Returns the name of the protocol.
+ *
+ * @return the protocol name
+ */
+ public final String getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * Returns the major version number of the protocol.
+ *
+ * @return the major version number.
+ */
+ public final int getMajor() {
+ return major;
+ }
+
+ /**
+ * Returns the minor version number of the HTTP protocol.
+ *
+ * @return the minor version number.
+ */
+ public final int getMinor() {
+ return minor;
+ }
+
+
+ /**
+ * Obtains a specific version of this protocol.
+ * This can be used by derived classes to instantiate themselves instead
+ * of the base class, and to define constants for commonly used versions.
+ * <br/>
+ * The default implementation in this class returns <code>this</code>
+ * if the version matches, and creates a new {@link ProtocolVersion}
+ * otherwise.
+ *
+ * @param major the major version
+ * @param minor the minor version
+ *
+ * @return a protocol version with the same protocol name
+ * and the argument version
+ */
+ public ProtocolVersion forVersion(int major, int minor) {
+
+ if ((major == this.major) && (minor == this.minor)) {
+ return this;
+ }
+
+ // argument checking is done in the constructor
+ return new ProtocolVersion(this.protocol, major, minor);
+ }
+
+
+ /**
+ * Obtains a hash code consistent with {@link #equals}.
+ *
+ * @return the hashcode of this protocol version
+ */
+ public final int hashCode() {
+ return this.protocol.hashCode() ^ (this.major * 100000) ^ this.minor;
+ }
+
+
+ /**
+ * Checks equality of this protocol version with an object.
+ * The object is equal if it is a protocl version with the same
+ * protocol name, major version number, and minor version number.
+ * The specific class of the object is <i>not</i> relevant,
+ * instances of derived classes with identical attributes are
+ * equal to instances of the base class and vice versa.
+ *
+ * @param obj the object to compare with
+ *
+ * @return <code>true</code> if the argument is the same protocol version,
+ * <code>false</code> otherwise
+ */
+ public final boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ProtocolVersion)) {
+ return false;
+ }
+ ProtocolVersion that = (ProtocolVersion) obj;
+
+ return ((this.protocol.equals(that.protocol)) &&
+ (this.major == that.major) &&
+ (this.minor == that.minor));
+ }
+
+
+ /**
+ * Checks whether this protocol can be compared to another one.
+ * Only protocol versions with the same protocol name can be
+ * {@link #compareToVersion compared}.
+ *
+ * @param that the protocol version to consider
+ *
+ * @return <code>true</code> if {@link #compareToVersion compareToVersion}
+ * can be called with the argument, <code>false</code> otherwise
+ */
+ public boolean isComparable(ProtocolVersion that) {
+ return (that != null) && this.protocol.equals(that.protocol);
+ }
+
+
+ /**
+ * Compares this protocol version with another one.
+ * Only protocol versions with the same protocol name can be compared.
+ * This method does <i>not</i> define a total ordering, as it would be
+ * required for {@link java.lang.Comparable}.
+ *
+ * @param that the protocl version to compare with
+ *
+ * @return a negative integer, zero, or a positive integer
+ * as this version is less than, equal to, or greater than
+ * the argument version.
+ *
+ * @throws IllegalArgumentException
+ * if the argument has a different protocol name than this object,
+ * or if the argument is <code>null</code>
+ */
+ public int compareToVersion(ProtocolVersion that) {
+ if (that == null) {
+ throw new IllegalArgumentException
+ ("Protocol version must not be null.");
+ }
+ if (!this.protocol.equals(that.protocol)) {
+ throw new IllegalArgumentException
+ ("Versions for different protocols cannot be compared. " +
+ this + " " + that);
+ }
+
+ int delta = getMajor() - that.getMajor();
+ if (delta == 0) {
+ delta = getMinor() - that.getMinor();
+ }
+ return delta;
+ }
+
+
+ /**
+ * Tests if this protocol version is greater or equal to the given one.
+ *
+ * @param version the version against which to check this version
+ *
+ * @return <code>true</code> if this protocol version is
+ * {@link #isComparable comparable} to the argument
+ * and {@link #compareToVersion compares} as greater or equal,
+ * <code>false</code> otherwise
+ */
+ public final boolean greaterEquals(ProtocolVersion version) {
+ return isComparable(version) && (compareToVersion(version) >= 0);
+ }
+
+
+ /**
+ * Tests if this protocol version is less or equal to the given one.
+ *
+ * @param version the version against which to check this version
+ *
+ * @return <code>true</code> if this protocol version is
+ * {@link #isComparable comparable} to the argument
+ * and {@link #compareToVersion compares} as less or equal,
+ * <code>false</code> otherwise
+ */
+ public final boolean lessEquals(ProtocolVersion version) {
+ return isComparable(version) && (compareToVersion(version) <= 0);
+ }
+
+
+ /**
+ * Converts this protocol version to a string.
+ *
+ * @return a protocol version string, like "HTTP/1.1"
+ */
+ public String toString() {
+ CharArrayBuffer buffer = new CharArrayBuffer(16);
+ buffer.append(this.protocol);
+ buffer.append('/');
+ buffer.append(Integer.toString(this.major));
+ buffer.append('.');
+ buffer.append(Integer.toString(this.minor));
+ return buffer.toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/ReasonPhraseCatalog.java b/src/org/apache/http/ReasonPhraseCatalog.java
new file mode 100644
index 0000000..12ad6d9
--- /dev/null
+++ b/src/org/apache/http/ReasonPhraseCatalog.java
@@ -0,0 +1,63 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/ReasonPhraseCatalog.java $
+ * $Revision: 505744 $
+ * $Date: 2007-02-10 10:58:45 -0800 (Sat, 10 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import java.util.Locale;
+
+
+/**
+ * Interface for obtaining reason phrases for HTTP status codes.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 505744 $
+ *
+ * @since 4.0
+ */
+public interface ReasonPhraseCatalog {
+
+ /**
+ * Obtains the reason phrase for a status code.
+ * The optional context allows for catalogs that detect
+ * the language for the reason phrase.
+ *
+ * @param status the status code, in the range 100-599
+ * @param loc the preferred locale for the reason phrase
+ *
+ * @return the reason phrase, or <code>null</code> if unknown
+ */
+ public String getReason(int status, Locale loc)
+ ;
+
+}
diff --git a/src/org/apache/http/RequestLine.java b/src/org/apache/http/RequestLine.java
new file mode 100644
index 0000000..e865929
--- /dev/null
+++ b/src/org/apache/http/RequestLine.java
@@ -0,0 +1,53 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/RequestLine.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * The first line of an {@link HttpRequest HttpRequest}.
+ * It contains the method, URI, and HTTP version of the request.
+ * For details, see RFC 2616.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public interface RequestLine {
+
+ String getMethod();
+
+ ProtocolVersion getProtocolVersion();
+
+ String getUri();
+
+}
diff --git a/src/org/apache/http/StatusLine.java b/src/org/apache/http/StatusLine.java
new file mode 100644
index 0000000..aa8a3bc
--- /dev/null
+++ b/src/org/apache/http/StatusLine.java
@@ -0,0 +1,55 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/StatusLine.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+/**
+ * Represents a status line as returned from a HTTP server.
+ * See <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>,
+ * section 6.1.
+ * Implementations are expected to be thread safe.
+ *
+ * @see HttpStatus
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @version $Id: StatusLine.java 573864 2007-09-08 15:53:25Z rolandw $
+ *
+ * @since 4.0
+ */
+public interface StatusLine {
+
+ ProtocolVersion getProtocolVersion();
+
+ int getStatusCode();
+
+ String getReasonPhrase();
+
+}
diff --git a/src/org/apache/http/TokenIterator.java b/src/org/apache/http/TokenIterator.java
new file mode 100644
index 0000000..bfe3473
--- /dev/null
+++ b/src/org/apache/http/TokenIterator.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/TokenIterator.java $
+ * $Revision: 601000 $
+ * $Date: 2007-12-04 09:03:49 -0800 (Tue, 04 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+
+import java.util.Iterator;
+
+
+/**
+ * An iterator for {@link String} tokens.
+ * This interface is designed as a complement to
+ * {@link HeaderElementIterator}, in cases where the items
+ * are plain strings rather than full header elements.
+ *
+ * @version $Revision: 601000 $
+ */
+public interface TokenIterator extends Iterator {
+
+ /**
+ * Indicates whether there is another token in this iteration.
+ *
+ * @return <code>true</code> if there is another token,
+ * <code>false</code> otherwise
+ */
+ boolean hasNext()
+ ;
+
+
+ /**
+ * Obtains the next token from this iteration.
+ * This method should only be called while {@link #hasNext hasNext}
+ * is true.
+ *
+ * @return the next token in this iteration
+ */
+ String nextToken()
+ ;
+}
diff --git a/src/org/apache/http/UnsupportedHttpVersionException.java b/src/org/apache/http/UnsupportedHttpVersionException.java
new file mode 100644
index 0000000..716d7a5
--- /dev/null
+++ b/src/org/apache/http/UnsupportedHttpVersionException.java
@@ -0,0 +1,64 @@
+/*
+ * $HeadURL:https://svn.apache.org/repos/asf/jakarta/httpcomponents/trunk/coyote-httpconnector/src/java/org/apache/http/tcconnector/UnsupportedHttpVersionException.java $
+ * $Revision:379772 $
+ * $Date:2006-02-22 14:52:29 +0100 (Wed, 22 Feb 2006) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http;
+
+import org.apache.http.ProtocolException;
+
+/**
+ * Indicates an unsupported version of the HTTP protocol.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision:379772 $
+ */
+public class UnsupportedHttpVersionException extends ProtocolException {
+
+ private static final long serialVersionUID = -1348448090193107031L;
+
+
+ /**
+ * Creates an exception without a detail message.
+ */
+ public UnsupportedHttpVersionException() {
+ super();
+ }
+
+ /**
+ * Creates an exception with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public UnsupportedHttpVersionException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/auth/AUTH.java b/src/org/apache/http/auth/AUTH.java
new file mode 100644
index 0000000..8ab6dc2
--- /dev/null
+++ b/src/org/apache/http/auth/AUTH.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AUTH.java $
+ * $Revision: 618365 $
+ * $Date: 2008-02-04 10:20:08 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+/**
+ * Constants and static helpers related to the HTTP authentication.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public final class AUTH {
+
+ /**
+ * The www authenticate challange header.
+ */
+ public static final String WWW_AUTH = "WWW-Authenticate";
+
+ /**
+ * The www authenticate response header.
+ */
+ public static final String WWW_AUTH_RESP = "Authorization";
+
+ /**
+ * The proxy authenticate challange header.
+ */
+ public static final String PROXY_AUTH = "Proxy-Authenticate";
+
+ /**
+ * The proxy authenticate response header.
+ */
+ public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
+
+ private AUTH() {
+ }
+
+}
diff --git a/src/org/apache/http/auth/AuthScheme.java b/src/org/apache/http/auth/AuthScheme.java
new file mode 100644
index 0000000..bdaebdb
--- /dev/null
+++ b/src/org/apache/http/auth/AuthScheme.java
@@ -0,0 +1,140 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AuthScheme.java $
+ * $Revision: 537144 $
+ * $Date: 2007-05-11 02:30:13 -0700 (Fri, 11 May 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import org.apache.http.Header;
+import org.apache.http.HttpRequest;
+
+/**
+ * <p>
+ * This interface represents an abstract challenge-response oriented
+ * authentication scheme.
+ * </p>
+ * <p>
+ * An authentication scheme should be able to support the following
+ * functions:
+ * <ul>
+ * <li>Parse and process the challenge sent by the targer server
+ * in response to request for a protected resource
+ * <li>Provide its textual designation
+ * <li>Provide its parameters, if available
+ * <li>Provide the realm this authentication scheme is applicable to,
+ * if available
+ * <li>Generate authorization string for the given set of credentials,
+ * request method and URI as specificed in the HTTP request line
+ * in response to the actual authorization challenge
+ * </ul>
+ * </p>
+ * <p>
+ * Authentication schemes may ignore method name and URI parameters
+ * if they are not relevant for the given authentication mechanism
+ * </p>
+ * <p>
+ * Authentication schemes may be stateful involving a series of
+ * challenge-response exchanges
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
+ *
+ * @since 4.0
+ */
+
+public interface AuthScheme {
+
+ /**
+ * Processes the given challenge token. Some authentication schemes
+ * may involve multiple challenge-response exchanges. Such schemes must be able
+ * to maintain the state information when dealing with sequential challenges
+ *
+ * @param header the challenge header
+ */
+ void processChallenge(final Header header) throws MalformedChallengeException;
+
+ /**
+ * Returns textual designation of the given authentication scheme.
+ *
+ * @return the name of the given authentication scheme
+ */
+ String getSchemeName();
+
+ /**
+ * Returns authentication parameter with the given name, if available.
+ *
+ * @param name The name of the parameter to be returned
+ *
+ * @return the parameter with the given name
+ */
+ String getParameter(final String name);
+
+ /**
+ * Returns authentication realm. If the concept of an authentication
+ * realm is not applicable to the given authentication scheme, returns
+ * <code>null</code>.
+ *
+ * @return the authentication realm
+ */
+ String getRealm();
+
+ /**
+ * Tests if the authentication scheme is provides authorization on a per
+ * connection basis instead of usual per request basis
+ *
+ * @return <tt>true</tt> if the scheme is connection based, <tt>false</tt>
+ * if the scheme is request based.
+ */
+ boolean isConnectionBased();
+
+ /**
+ * Authentication process may involve a series of challenge-response exchanges.
+ * This method tests if the authorization process has been completed, either
+ * successfully or unsuccessfully, that is, all the required authorization
+ * challenges have been processed in their entirety.
+ *
+ * @return <tt>true</tt> if the authentication process has been completed,
+ * <tt>false</tt> otherwise.
+ */
+ boolean isComplete();
+
+ /**
+ * Produces an authorization string for the given set of {@link Credentials}.
+ *
+ * @param credentials The set of credentials to be used for athentication
+ * @param request The request being authenticated
+ * @throws AuthenticationException if authorization string cannot
+ * be generated due to an authentication failure
+ *
+ * @return the authorization string
+ */
+ Header authenticate(Credentials credentials, HttpRequest request)
+ throws AuthenticationException;
+
+}
diff --git a/src/org/apache/http/auth/AuthSchemeFactory.java b/src/org/apache/http/auth/AuthSchemeFactory.java
new file mode 100644
index 0000000..8f985b0
--- /dev/null
+++ b/src/org/apache/http/auth/AuthSchemeFactory.java
@@ -0,0 +1,46 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AuthSchemeFactory.java $
+ * $Revision: 527900 $
+ * $Date: 2007-04-12 05:35:25 -0700 (Thu, 12 Apr 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface AuthSchemeFactory {
+
+ AuthScheme newInstance(HttpParams params);
+
+}
diff --git a/src/org/apache/http/auth/AuthSchemeRegistry.java b/src/org/apache/http/auth/AuthSchemeRegistry.java
new file mode 100644
index 0000000..62a5d4d
--- /dev/null
+++ b/src/org/apache/http/auth/AuthSchemeRegistry.java
@@ -0,0 +1,149 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AuthSchemeRegistry.java $
+ * $Revision: 652950 $
+ * $Date: 2008-05-02 16:49:48 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ * Authentication scheme registry that can be used to obtain the corresponding
+ * authentication scheme implementation for a given type of authorization challenge.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * @version $Revision: 652950 $
+ * @since 4.0
+ */
+public final class AuthSchemeRegistry {
+
+ private final Map<String,AuthSchemeFactory> registeredSchemes;
+
+ public AuthSchemeRegistry() {
+ super();
+ this.registeredSchemes = new LinkedHashMap<String,AuthSchemeFactory>();
+ }
+
+ /**
+ * Registers a {@link AuthSchemeFactory} with the given identifier. If a factory with the
+ * given name already exists it will be overridden. This name is the same one used to
+ * retrieve the {@link AuthScheme authentication scheme} from {@link #getAuthScheme}.
+ *
+ * <p>
+ * Please note that custom authentication preferences, if used, need to be updated accordingly
+ * for the new {@link AuthScheme authentication scheme} to take effect.
+ * </p>
+ *
+ * @param name the identifier for this scheme
+ * @param factory the {@link AuthSchemeFactory} class to register
+ *
+ * @see #getAuthScheme
+ */
+ public synchronized void register(
+ final String name,
+ final AuthSchemeFactory factory) {
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ if (factory == null) {
+ throw new IllegalArgumentException("Authentication scheme factory may not be null");
+ }
+ registeredSchemes.put(name.toLowerCase(Locale.ENGLISH), factory);
+ }
+
+ /**
+ * Unregisters the class implementing an {@link AuthScheme authentication scheme} with
+ * the given name.
+ *
+ * @param name the identifier of the class to unregister
+ */
+ public synchronized void unregister(final String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ registeredSchemes.remove(name.toLowerCase(Locale.ENGLISH));
+ }
+
+ /**
+ * Gets the {@link AuthScheme authentication scheme} with the given name.
+ *
+ * @param name the {@link AuthScheme authentication scheme} identifier
+ * @param params the {@link HttpParams HTTP parameters} for the authentication
+ * scheme.
+ *
+ * @return {@link AuthScheme authentication scheme}
+ *
+ * @throws IllegalStateException if a scheme with the given name cannot be found
+ */
+ public synchronized AuthScheme getAuthScheme(final String name, final HttpParams params)
+ throws IllegalStateException {
+
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ AuthSchemeFactory factory = registeredSchemes.get(name.toLowerCase(Locale.ENGLISH));
+ if (factory != null) {
+ return factory.newInstance(params);
+ } else {
+ throw new IllegalStateException("Unsupported authentication scheme: " + name);
+ }
+ }
+
+ /**
+ * Obtains a list containing names of all registered {@link AuthScheme authentication
+ * schemes} in their default order.
+ *
+ * @return list of registered scheme names
+ */
+ public synchronized List<String> getSchemeNames() {
+ return new ArrayList<String>(registeredSchemes.keySet());
+ }
+
+ /**
+ * Populates the internal collection of registered {@link AuthScheme authentication schemes}
+ * with the content of the map passed as a parameter.
+ *
+ * @param map authentication schemes
+ */
+ public synchronized void setItems(final Map<String, AuthSchemeFactory> map) {
+ if (map == null) {
+ return;
+ }
+ registeredSchemes.clear();
+ registeredSchemes.putAll(map);
+ }
+
+}
diff --git a/src/org/apache/http/auth/AuthScope.java b/src/org/apache/http/auth/AuthScope.java
new file mode 100644
index 0000000..c9d7f56
--- /dev/null
+++ b/src/org/apache/http/auth/AuthScope.java
@@ -0,0 +1,292 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AuthScope.java $
+ * $Revision: 652950 $
+ * $Date: 2008-05-02 16:49:48 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.util.Locale;
+
+import org.apache.http.util.LangUtils;
+
+/**
+ * The class represents an authentication scope consisting of a host name,
+ * a port number, a realm name and an authentication scheme name which
+ * {@link Credentials Credentials} apply to.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:adrian@intencha.com">Adrian Sutton</a>
+ *
+ * @since 4.0
+ */
+public class AuthScope {
+
+ /**
+ * The <tt>null</tt> value represents any host. In the future versions of
+ * HttpClient the use of this parameter will be discontinued.
+ */
+ public static final String ANY_HOST = null;
+
+ /**
+ * The <tt>-1</tt> value represents any port.
+ */
+ public static final int ANY_PORT = -1;
+
+ /**
+ * The <tt>null</tt> value represents any realm.
+ */
+ public static final String ANY_REALM = null;
+
+ /**
+ * The <tt>null</tt> value represents any authentication scheme.
+ */
+ public static final String ANY_SCHEME = null;
+
+ /**
+ * Default scope matching any host, port, realm and authentication scheme.
+ * In the future versions of HttpClient the use of this parameter will be
+ * discontinued.
+ */
+ public static final AuthScope ANY = new AuthScope(ANY_HOST, ANY_PORT, ANY_REALM, ANY_SCHEME);
+
+ /** The authentication scheme the credentials apply to. */
+ private final String scheme;
+
+ /** The realm the credentials apply to. */
+ private final String realm;
+
+ /** The host the credentials apply to. */
+ private final String host;
+
+ /** The port the credentials apply to. */
+ private final int port;
+
+ /** Creates a new credentials scope for the given
+ * <tt>host</tt>, <tt>port</tt>, <tt>realm</tt>, and
+ * <tt>authentication scheme</tt>.
+ *
+ * @param host the host the credentials apply to. May be set
+ * to <tt>null</tt> if credenticals are applicable to
+ * any host.
+ * @param port the port the credentials apply to. May be set
+ * to negative value if credenticals are applicable to
+ * any port.
+ * @param realm the realm the credentials apply to. May be set
+ * to <tt>null</tt> if credenticals are applicable to
+ * any realm.
+ * @param scheme the authentication scheme the credentials apply to.
+ * May be set to <tt>null</tt> if credenticals are applicable to
+ * any authentication scheme.
+ */
+ public AuthScope(final String host, int port,
+ final String realm, final String scheme)
+ {
+ this.host = (host == null) ? ANY_HOST: host.toLowerCase(Locale.ENGLISH);
+ this.port = (port < 0) ? ANY_PORT: port;
+ this.realm = (realm == null) ? ANY_REALM: realm;
+ this.scheme = (scheme == null) ? ANY_SCHEME: scheme.toUpperCase(Locale.ENGLISH);
+ }
+
+ /** Creates a new credentials scope for the given
+ * <tt>host</tt>, <tt>port</tt>, <tt>realm</tt>, and any
+ * authentication scheme.
+ *
+ * @param host the host the credentials apply to. May be set
+ * to <tt>null</tt> if credenticals are applicable to
+ * any host.
+ * @param port the port the credentials apply to. May be set
+ * to negative value if credenticals are applicable to
+ * any port.
+ * @param realm the realm the credentials apply to. May be set
+ * to <tt>null</tt> if credenticals are applicable to
+ * any realm.
+ */
+ public AuthScope(final String host, int port, final String realm) {
+ this(host, port, realm, ANY_SCHEME);
+ }
+
+ /** Creates a new credentials scope for the given
+ * <tt>host</tt>, <tt>port</tt>, any realm name, and any
+ * authentication scheme.
+ *
+ * @param host the host the credentials apply to. May be set
+ * to <tt>null</tt> if credenticals are applicable to
+ * any host.
+ * @param port the port the credentials apply to. May be set
+ * to negative value if credenticals are applicable to
+ * any port.
+ */
+ public AuthScope(final String host, int port) {
+ this(host, port, ANY_REALM, ANY_SCHEME);
+ }
+
+ /**
+ * Creates a copy of the given credentials scope.
+ */
+ public AuthScope(final AuthScope authscope) {
+ super();
+ if (authscope == null) {
+ throw new IllegalArgumentException("Scope may not be null");
+ }
+ this.host = authscope.getHost();
+ this.port = authscope.getPort();
+ this.realm = authscope.getRealm();
+ this.scheme = authscope.getScheme();
+ }
+
+ /**
+ * @return the host
+ */
+ public String getHost() {
+ return this.host;
+ }
+
+ /**
+ * @return the port
+ */
+ public int getPort() {
+ return this.port;
+ }
+
+ /**
+ * @return the realm name
+ */
+ public String getRealm() {
+ return this.realm;
+ }
+
+ /**
+ * @return the scheme type
+ */
+ public String getScheme() {
+ return this.scheme;
+ }
+
+ /**
+ * Tests if the authentication scopes match.
+ *
+ * @return the match factor. Negative value signifies no match.
+ * Non-negative signifies a match. The greater the returned value
+ * the closer the match.
+ */
+ public int match(final AuthScope that) {
+ int factor = 0;
+ if (LangUtils.equals(this.scheme, that.scheme)) {
+ factor += 1;
+ } else {
+ if (this.scheme != ANY_SCHEME && that.scheme != ANY_SCHEME) {
+ return -1;
+ }
+ }
+ if (LangUtils.equals(this.realm, that.realm)) {
+ factor += 2;
+ } else {
+ if (this.realm != ANY_REALM && that.realm != ANY_REALM) {
+ return -1;
+ }
+ }
+ if (this.port == that.port) {
+ factor += 4;
+ } else {
+ if (this.port != ANY_PORT && that.port != ANY_PORT) {
+ return -1;
+ }
+ }
+ if (LangUtils.equals(this.host, that.host)) {
+ factor += 8;
+ } else {
+ if (this.host != ANY_HOST && that.host != ANY_HOST) {
+ return -1;
+ }
+ }
+ return factor;
+ }
+
+ /**
+ * @see java.lang.Object#equals(Object)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof AuthScope)) {
+ return super.equals(o);
+ }
+ AuthScope that = (AuthScope) o;
+ return
+ LangUtils.equals(this.host, that.host)
+ && this.port == that.port
+ && LangUtils.equals(this.realm, that.realm)
+ && LangUtils.equals(this.scheme, that.scheme);
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ if (this.scheme != null) {
+ buffer.append(this.scheme.toUpperCase(Locale.ENGLISH));
+ buffer.append(' ');
+ }
+ if (this.realm != null) {
+ buffer.append('\'');
+ buffer.append(this.realm);
+ buffer.append('\'');
+ } else {
+ buffer.append("<any realm>");
+ }
+ if (this.host != null) {
+ buffer.append('@');
+ buffer.append(this.host);
+ if (this.port >= 0) {
+ buffer.append(':');
+ buffer.append(this.port);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.host);
+ hash = LangUtils.hashCode(hash, this.port);
+ hash = LangUtils.hashCode(hash, this.realm);
+ hash = LangUtils.hashCode(hash, this.scheme);
+ return hash;
+ }
+}
diff --git a/src/org/apache/http/auth/AuthState.java b/src/org/apache/http/auth/AuthState.java
new file mode 100644
index 0000000..f55bf86
--- /dev/null
+++ b/src/org/apache/http/auth/AuthState.java
@@ -0,0 +1,147 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AuthState.java $
+ * $Revision: 659971 $
+ * $Date: 2008-05-25 05:01:22 -0700 (Sun, 25 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+
+/**
+ * This class provides detailed information about the state of the
+ * authentication process.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class AuthState {
+
+ /** Actual authentication scheme */
+ private AuthScheme authScheme;
+
+ /** Actual authentication scope */
+ private AuthScope authScope;
+
+ /** Credentials selected for authentication */
+ private Credentials credentials;
+
+ /**
+ * Default constructor.
+ *
+ */
+ public AuthState() {
+ super();
+ }
+
+ /**
+ * Invalidates the authentication state by resetting its parameters.
+ */
+ public void invalidate() {
+ this.authScheme = null;
+ this.authScope = null;
+ this.credentials = null;
+ }
+
+ public boolean isValid() {
+ return this.authScheme != null;
+ }
+
+ /**
+ * Assigns the given {@link AuthScheme authentication scheme}.
+ *
+ * @param authScheme the {@link AuthScheme authentication scheme}
+ */
+ public void setAuthScheme(final AuthScheme authScheme) {
+ if (authScheme == null) {
+ invalidate();
+ return;
+ }
+ this.authScheme = authScheme;
+ }
+
+ /**
+ * Returns the {@link AuthScheme authentication scheme}.
+ *
+ * @return {@link AuthScheme authentication scheme}
+ */
+ public AuthScheme getAuthScheme() {
+ return this.authScheme;
+ }
+
+
+ /**
+ * Returns user {@link Credentials} selected for authentication if available
+ *
+ * @return user credentials if available, <code>null</code otherwise
+ */
+ public Credentials getCredentials() {
+ return this.credentials;
+ }
+
+
+ /**
+ * Sets user {@link Credentials} to be used for authentication
+ *
+ * @param credentials User credentials
+ */
+ public void setCredentials(final Credentials credentials) {
+ this.credentials = credentials;
+ }
+
+
+ /**
+ * Returns actual {@link AuthScope} if available
+ *
+ * @return actual authentication scope if available, <code>null</code otherwise
+ */
+ public AuthScope getAuthScope() {
+ return this.authScope;
+ }
+
+ /**
+ * Sets actual {@link AuthScope}.
+ *
+ * @param authScope Authentication scope
+ */
+ public void setAuthScope(final AuthScope authScope) {
+ this.authScope = authScope;
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("auth scope [");
+ buffer.append(this.authScope);
+ buffer.append("]; credentials set [");
+ buffer.append(this.credentials != null ? "true" : "false");
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/auth/AuthenticationException.java b/src/org/apache/http/auth/AuthenticationException.java
new file mode 100644
index 0000000..8b307be
--- /dev/null
+++ b/src/org/apache/http/auth/AuthenticationException.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/AuthenticationException.java $
+ * $Revision: 505684 $
+ * $Date: 2007-02-10 04:40:02 -0800 (Sat, 10 Feb 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import org.apache.http.ProtocolException;
+
+/**
+ * Signals a failure in authentication process
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class AuthenticationException extends ProtocolException {
+
+ private static final long serialVersionUID = -6794031905674764776L;
+
+ /**
+ * Creates a new AuthenticationException with a <tt>null</tt> detail message.
+ */
+ public AuthenticationException() {
+ super();
+ }
+
+ /**
+ * Creates a new AuthenticationException with the specified message.
+ *
+ * @param message the exception detail message
+ */
+ public AuthenticationException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new AuthenticationException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public AuthenticationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/org/apache/http/auth/BasicUserPrincipal.java b/src/org/apache/http/auth/BasicUserPrincipal.java
new file mode 100644
index 0000000..2485011
--- /dev/null
+++ b/src/org/apache/http/auth/BasicUserPrincipal.java
@@ -0,0 +1,90 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/BasicUserPrincipal.java $
+ * $Revision: 658430 $
+ * $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.security.Principal;
+
+import org.apache.http.util.LangUtils;
+
+/**
+ * Basic user principal used for HTTP authentication
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public final class BasicUserPrincipal implements Principal {
+
+ private final String username;
+
+ public BasicUserPrincipal(final String username) {
+ super();
+ if (username == null) {
+ throw new IllegalArgumentException("User name may not be null");
+ }
+ this.username = username;
+ }
+
+ public String getName() {
+ return this.username;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.username);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (this == o) return true;
+ if (o instanceof BasicUserPrincipal) {
+ BasicUserPrincipal that = (BasicUserPrincipal) o;
+ if (LangUtils.equals(this.username, that.username)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("[principal: ");
+ buffer.append(this.username);
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
+
diff --git a/src/org/apache/http/auth/Credentials.java b/src/org/apache/http/auth/Credentials.java
new file mode 100644
index 0000000..846a23b
--- /dev/null
+++ b/src/org/apache/http/auth/Credentials.java
@@ -0,0 +1,49 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/Credentials.java $
+ * $Revision: 658430 $
+ * $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.security.Principal;
+
+/**
+ * User name and password based authentication credentials.
+ *
+ * @author Unascribed
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @version $Revision: 658430 $ $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ */
+public interface Credentials {
+
+ Principal getUserPrincipal();
+
+ String getPassword();
+
+}
diff --git a/src/org/apache/http/auth/InvalidCredentialsException.java b/src/org/apache/http/auth/InvalidCredentialsException.java
new file mode 100644
index 0000000..50155ec
--- /dev/null
+++ b/src/org/apache/http/auth/InvalidCredentialsException.java
@@ -0,0 +1,71 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/InvalidCredentialsException.java $
+ * $Revision: 505684 $
+ * $Date: 2007-02-10 04:40:02 -0800 (Sat, 10 Feb 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+/**
+ * Authentication credentials required to respond to a authentication
+ * challenge are invalid
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class InvalidCredentialsException extends AuthenticationException {
+
+ private static final long serialVersionUID = -4834003835215460648L;
+
+ /**
+ * Creates a new InvalidCredentialsException with a <tt>null</tt> detail message.
+ */
+ public InvalidCredentialsException() {
+ super();
+ }
+
+ /**
+ * Creates a new InvalidCredentialsException with the specified message.
+ *
+ * @param message the exception detail message
+ */
+ public InvalidCredentialsException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new InvalidCredentialsException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public InvalidCredentialsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/auth/MalformedChallengeException.java b/src/org/apache/http/auth/MalformedChallengeException.java
new file mode 100644
index 0000000..8c7e373
--- /dev/null
+++ b/src/org/apache/http/auth/MalformedChallengeException.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/MalformedChallengeException.java $
+ * $Revision: 505684 $
+ * $Date: 2007-02-10 04:40:02 -0800 (Sat, 10 Feb 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import org.apache.http.ProtocolException;
+
+/**
+ * Signals that authentication challenge is in some way invalid or
+ * illegal in the given context
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class MalformedChallengeException extends ProtocolException {
+
+ private static final long serialVersionUID = 814586927989932284L;
+
+ /**
+ * Creates a new MalformedChallengeException with a <tt>null</tt> detail message.
+ */
+ public MalformedChallengeException() {
+ super();
+ }
+
+ /**
+ * Creates a new MalformedChallengeException with the specified message.
+ *
+ * @param message the exception detail message
+ */
+ public MalformedChallengeException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new MalformedChallengeException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public MalformedChallengeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/auth/NTCredentials.java b/src/org/apache/http/auth/NTCredentials.java
new file mode 100644
index 0000000..6800c42
--- /dev/null
+++ b/src/org/apache/http/auth/NTCredentials.java
@@ -0,0 +1,180 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/NTCredentials.java $
+ * $Revision: 658430 $
+ * $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.security.Principal;
+import java.util.Locale;
+
+import org.apache.http.util.LangUtils;
+
+/** {@link Credentials} specific to the Windows platform.
+ *
+ * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 2.0
+ */
+public class NTCredentials implements Credentials {
+
+ /** The user principal */
+ private final NTUserPrincipal principal;
+
+ /** Password */
+ private final String password;
+
+ /** The host the authentication request is originating from. */
+ private final String workstation;
+
+ /**
+ * The constructor with the fully qualified username and password combined
+ * string argument.
+ *
+ * @param usernamePassword the domain/username:password formed string
+ */
+ public NTCredentials(String usernamePassword) {
+ super();
+ if (usernamePassword == null) {
+ throw new IllegalArgumentException("Username:password string may not be null");
+ }
+ String username;
+ int atColon = usernamePassword.indexOf(':');
+ if (atColon >= 0) {
+ username = usernamePassword.substring(0, atColon);
+ this.password = usernamePassword.substring(atColon + 1);
+ } else {
+ username = usernamePassword;
+ this.password = null;
+ }
+ int atSlash = username.indexOf('/');
+ if (atSlash >= 0) {
+ this.principal = new NTUserPrincipal(
+ username.substring(0, atSlash).toUpperCase(Locale.ENGLISH),
+ username.substring(atSlash + 1));
+ } else {
+ this.principal = new NTUserPrincipal(
+ null,
+ username.substring(atSlash + 1));
+ }
+ this.workstation = null;
+ }
+
+ /**
+ * Constructor.
+ * @param userName The user name. This should not include the domain to authenticate with.
+ * For example: "user" is correct whereas "DOMAIN\\user" is not.
+ * @param password The password.
+ * @param workstation The workstation the authentication request is originating from.
+ * Essentially, the computer name for this machine.
+ * @param domain The domain to authenticate within.
+ */
+ public NTCredentials(
+ final String userName,
+ final String password,
+ final String workstation,
+ final String domain) {
+ super();
+ if (userName == null) {
+ throw new IllegalArgumentException("User name may not be null");
+ }
+ this.principal = new NTUserPrincipal(domain, userName);
+ this.password = password;
+ if (workstation != null) {
+ this.workstation = workstation.toUpperCase(Locale.ENGLISH);
+ } else {
+ this.workstation = null;
+ }
+ }
+
+ public Principal getUserPrincipal() {
+ return this.principal;
+ }
+
+ public String getUserName() {
+ return this.principal.getUsername();
+ }
+
+ public String getPassword() {
+ return this.password;
+ }
+
+ /**
+ * Retrieves the name to authenticate with.
+ *
+ * @return String the domain these credentials are intended to authenticate with.
+ */
+ public String getDomain() {
+ return this.principal.getDomain();
+ }
+
+ /**
+ * Retrieves the workstation name of the computer originating the request.
+ *
+ * @return String the workstation the user is logged into.
+ */
+ public String getWorkstation() {
+ return this.workstation;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.principal);
+ hash = LangUtils.hashCode(hash, this.workstation);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (this == o) return true;
+ if (o instanceof NTCredentials) {
+ NTCredentials that = (NTCredentials) o;
+ if (LangUtils.equals(this.principal, that.principal)
+ && LangUtils.equals(this.workstation, that.workstation)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("[principal: ");
+ buffer.append(this.principal);
+ buffer.append("][workstation: ");
+ buffer.append(this.workstation);
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/auth/NTUserPrincipal.java b/src/org/apache/http/auth/NTUserPrincipal.java
new file mode 100644
index 0000000..ac91bb8
--- /dev/null
+++ b/src/org/apache/http/auth/NTUserPrincipal.java
@@ -0,0 +1,113 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/NTUserPrincipal.java $
+ * $Revision: 658430 $
+ * $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.security.Principal;
+import java.util.Locale;
+
+import org.apache.http.util.LangUtils;
+
+/** NT (MS Windows specific) user principal used for HTTP authentication
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class NTUserPrincipal implements Principal {
+
+ private final String username;
+ private final String domain;
+ private final String ntname;
+
+ public NTUserPrincipal(
+ final String domain,
+ final String username) {
+ super();
+ if (username == null) {
+ throw new IllegalArgumentException("User name may not be null");
+ }
+ this.username = username;
+ if (domain != null) {
+ this.domain = domain.toUpperCase(Locale.ENGLISH);
+ } else {
+ this.domain = null;
+ }
+ if (this.domain != null && this.domain.length() > 0) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(this.domain);
+ buffer.append('/');
+ buffer.append(this.username);
+ this.ntname = buffer.toString();
+ } else {
+ this.ntname = this.username;
+ }
+ }
+
+ public String getName() {
+ return this.ntname;
+ }
+
+ public String getDomain() {
+ return this.domain;
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.username);
+ hash = LangUtils.hashCode(hash, this.domain);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (this == o) return true;
+ if (o instanceof NTUserPrincipal) {
+ NTUserPrincipal that = (NTUserPrincipal) o;
+ if (LangUtils.equals(this.username, that.username)
+ && LangUtils.equals(this.domain, that.domain)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return this.ntname;
+ }
+
+}
diff --git a/src/org/apache/http/auth/UsernamePasswordCredentials.java b/src/org/apache/http/auth/UsernamePasswordCredentials.java
new file mode 100644
index 0000000..f82608c
--- /dev/null
+++ b/src/org/apache/http/auth/UsernamePasswordCredentials.java
@@ -0,0 +1,126 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/UsernamePasswordCredentials.java $
+ * $Revision: 658430 $
+ * $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth;
+
+import java.security.Principal;
+
+import org.apache.http.util.LangUtils;
+
+/**
+ * Username and password {@link Credentials}
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 658430 $ $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ */
+public class UsernamePasswordCredentials implements Credentials {
+
+ private final BasicUserPrincipal principal;
+ private final String password;
+
+ /**
+ * The constructor with the username and password combined string argument.
+ *
+ * @param usernamePassword the username:password formed string
+ * @see #toString
+ */
+ public UsernamePasswordCredentials(String usernamePassword) {
+ super();
+ if (usernamePassword == null) {
+ throw new IllegalArgumentException("Username:password string may not be null");
+ }
+ int atColon = usernamePassword.indexOf(':');
+ if (atColon >= 0) {
+ this.principal = new BasicUserPrincipal(usernamePassword.substring(0, atColon));
+ this.password = usernamePassword.substring(atColon + 1);
+ } else {
+ this.principal = new BasicUserPrincipal(usernamePassword);
+ this.password = null;
+ }
+ }
+
+
+ /**
+ * The constructor with the username and password arguments.
+ *
+ * @param userName the user name
+ * @param password the password
+ */
+ public UsernamePasswordCredentials(String userName, String password) {
+ super();
+ if (userName == null) {
+ throw new IllegalArgumentException("Username may not be null");
+ }
+ this.principal = new BasicUserPrincipal(userName);
+ this.password = password;
+ }
+
+ public Principal getUserPrincipal() {
+ return this.principal;
+ }
+
+ public String getUserName() {
+ return this.principal.getName();
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.principal.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (this == o) return true;
+ if (o instanceof UsernamePasswordCredentials) {
+ UsernamePasswordCredentials that = (UsernamePasswordCredentials) o;
+ if (LangUtils.equals(this.principal, that.principal)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return this.principal.toString();
+ }
+
+}
+
diff --git a/src/org/apache/http/auth/package.html b/src/org/apache/http/auth/package.html
new file mode 100644
index 0000000..1493dfb
--- /dev/null
+++ b/src/org/apache/http/auth/package.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The API for client-side HTTP authentication against a server,
+commonly referred to as <i>HttpAuth</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/auth/params/AuthPNames.java b/src/org/apache/http/auth/params/AuthPNames.java
new file mode 100644
index 0000000..a053435
--- /dev/null
+++ b/src/org/apache/http/auth/params/AuthPNames.java
@@ -0,0 +1,56 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/params/AuthPNames.java $
+ * $Revision: 578403 $
+ * $Date: 2007-09-22 03:56:04 -0700 (Sat, 22 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth.params;
+
+/**
+ * Parameter names for HttpAuth.
+ *
+ * @version $Revision: 578403 $
+ *
+ * @since 4.0
+ */
+public interface AuthPNames {
+
+ /**
+ * Defines the charset to be used when encoding
+ * {@link org.apache.http.auth.Credentials}.
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * If not defined, then
+ * {@link org.apache.http.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET
+ * HttpProtocolParams.HTTP_ELEMENT_CHARSET}
+ * should be used.
+ * </p>
+ */
+ public static final String CREDENTIAL_CHARSET = "http.auth.credential-charset";
+
+}
diff --git a/src/org/apache/http/auth/params/AuthParamBean.java b/src/org/apache/http/auth/params/AuthParamBean.java
new file mode 100644
index 0000000..5b27328
--- /dev/null
+++ b/src/org/apache/http/auth/params/AuthParamBean.java
@@ -0,0 +1,47 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/params/AuthParamBean.java $
+ * $Revision: 632313 $
+ * $Date: 2008-02-29 05:19:50 -0800 (Fri, 29 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth.params;
+
+import org.apache.http.params.HttpAbstractParamBean;
+import org.apache.http.params.HttpParams;
+
+public class AuthParamBean extends HttpAbstractParamBean {
+
+ public AuthParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ public void setCredentialCharset (final String charset) {
+ AuthParams.setCredentialCharset(params, charset);
+ }
+
+}
diff --git a/src/org/apache/http/auth/params/AuthParams.java b/src/org/apache/http/auth/params/AuthParams.java
new file mode 100644
index 0000000..a724a8c
--- /dev/null
+++ b/src/org/apache/http/auth/params/AuthParams.java
@@ -0,0 +1,94 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/params/AuthParams.java $
+ * $Revision: 618365 $
+ * $Date: 2008-02-04 10:20:08 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.auth.params;
+
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * This class implements an adaptor around the {@link HttpParams} interface
+ * to simplify manipulation of the HTTP authentication specific parameters.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618365 $
+ *
+ * @since 4.0
+ *
+ * @see AuthPNames
+ */
+public final class AuthParams {
+
+ private AuthParams() {
+ super();
+ }
+
+ /**
+ * Obtains the charset for encoding
+ * {@link org.apache.http.auth.Credentials}.
+ * If not configured,
+ * {@link HTTP#DEFAULT_PROTOCOL_CHARSET HTTP.DEFAULT_PROTOCOL_CHARSET}
+ * is used instead.
+ *
+ * @return The charset
+ *
+ * @see AuthPNames#CREDENTIAL_CHARSET
+ */
+ public static String getCredentialCharset(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ String charset = (String) params.getParameter
+ (AuthPNames.CREDENTIAL_CHARSET);
+ //@@@ TODO: inconsistent with JavaDoc in AuthPNames,
+ //@@@ TODO: check HTTP_ELEMENT_CHARSET first, or fix JavaDocs
+ if (charset == null) {
+ charset = HTTP.DEFAULT_PROTOCOL_CHARSET;
+ }
+ return charset;
+ }
+
+
+ /**
+ * Sets the charset to be used when encoding
+ * {@link org.apache.http.auth.Credentials}.
+ *
+ * @param charset The charset
+ */
+ public static void setCredentialCharset(final HttpParams params, final String charset) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setParameter(AuthPNames.CREDENTIAL_CHARSET, charset);
+ }
+
+}
diff --git a/src/org/apache/http/auth/params/package.html b/src/org/apache/http/auth/params/package.html
new file mode 100644
index 0000000..f9258fd
--- /dev/null
+++ b/src/org/apache/http/auth/params/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/auth/params/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Parameters for configuring <i>HttpAuth</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/client/AuthenticationHandler.java b/src/org/apache/http/client/AuthenticationHandler.java
new file mode 100644
index 0000000..dacc1b8
--- /dev/null
+++ b/src/org/apache/http/client/AuthenticationHandler.java
@@ -0,0 +1,61 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/AuthenticationHandler.java $
+ * $Revision: 603318 $
+ * $Date: 2007-12-11 10:06:50 -0800 (Tue, 11 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.util.Map;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public interface AuthenticationHandler {
+
+ boolean isAuthenticationRequested(
+ HttpResponse response,
+ HttpContext context);
+
+ Map<String, Header> getChallenges(
+ HttpResponse response,
+ HttpContext context) throws MalformedChallengeException;
+
+ AuthScheme selectScheme(
+ Map<String, Header> challenges,
+ HttpResponse response,
+ HttpContext context) throws AuthenticationException;
+
+}
diff --git a/src/org/apache/http/client/CircularRedirectException.java b/src/org/apache/http/client/CircularRedirectException.java
new file mode 100644
index 0000000..08dca63
--- /dev/null
+++ b/src/org/apache/http/client/CircularRedirectException.java
@@ -0,0 +1,70 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/CircularRedirectException.java $
+ * $Revision: 558123 $
+ * $Date: 2007-07-20 13:29:58 -0700 (Fri, 20 Jul 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+/**
+ * Signals a circular redirect
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class CircularRedirectException extends RedirectException {
+
+ private static final long serialVersionUID = 6830063487001091803L;
+
+ /**
+ * Creates a new CircularRedirectException with a <tt>null</tt> detail message.
+ */
+ public CircularRedirectException() {
+ super();
+ }
+
+ /**
+ * Creates a new CircularRedirectException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public CircularRedirectException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new CircularRedirectException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public CircularRedirectException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/client/ClientProtocolException.java b/src/org/apache/http/client/ClientProtocolException.java
new file mode 100644
index 0000000..b5a991a
--- /dev/null
+++ b/src/org/apache/http/client/ClientProtocolException.java
@@ -0,0 +1,60 @@
+/*
+ * $HeadURL: $
+ * $Revision: $
+ * $Date: $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.io.IOException;
+
+/**
+ * Signals an error in the HTTP protocol.
+ */
+public class ClientProtocolException extends IOException {
+
+ private static final long serialVersionUID = -5596590843227115865L;
+
+ public ClientProtocolException() {
+ super();
+ }
+
+ public ClientProtocolException(String s) {
+ super(s);
+ }
+
+ public ClientProtocolException(Throwable cause) {
+ initCause(cause);
+ }
+
+ public ClientProtocolException(String message, Throwable cause) {
+ super(message);
+ initCause(cause);
+ }
+
+
+}
diff --git a/src/org/apache/http/client/CookieStore.java b/src/org/apache/http/client/CookieStore.java
new file mode 100644
index 0000000..bc239ac
--- /dev/null
+++ b/src/org/apache/http/client/CookieStore.java
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/CookieStore.java $
+ * $Revision: 604434 $
+ * $Date: 2007-12-15 06:45:48 -0800 (Sat, 15 Dec 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.http.cookie.Cookie;
+
+/**
+ * Abstract cookie store.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface CookieStore {
+
+ /**
+ * Adds an {@link Cookie HTTP cookie}, replacing any existing equivalent cookies.
+ * If the given cookie has already expired it will not be added, but existing
+ * values will still be removed.
+ *
+ * @param cookie the {@link Cookie cookie} to be added
+ */
+ void addCookie(Cookie cookie);
+
+ /**
+ * Returns all cookies contained in this store.
+ *
+ * @return all cookies
+ */
+ List<Cookie> getCookies();
+
+ /**
+ * Removes all of {@link Cookie cookies} in this store that have expired by
+ * the specified {@link java.util.Date date}.
+ *
+ * @return true if any cookies were purged.
+ */
+ boolean clearExpired(Date date);
+
+ /**
+ * Clears all cookies.
+ */
+ void clear();
+
+}
diff --git a/src/org/apache/http/client/CredentialsProvider.java b/src/org/apache/http/client/CredentialsProvider.java
new file mode 100644
index 0000000..8396d84
--- /dev/null
+++ b/src/org/apache/http/client/CredentialsProvider.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/CredentialsProvider.java $
+ * $Revision: 558124 $
+ * $Date: 2007-07-20 13:36:47 -0700 (Fri, 20 Jul 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+
+/**
+ * Abstract credentials provider.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface CredentialsProvider {
+
+ /**
+ * Sets the {@link Credentials credentials} for the given authentication
+ * scope. Any previous credentials for the given scope will be overwritten.
+ *
+ * @param authscope the {@link AuthScope authentication scope}
+ * @param credentials the authentication {@link Credentials credentials}
+ * for the given scope.
+ *
+ * @see #getCredentials(AuthScope)
+ */
+ void setCredentials(AuthScope authscope, Credentials credentials);
+
+ /**
+ * Get the {@link Credentials credentials} for the given authentication scope.
+ *
+ * @param authscope the {@link AuthScope authentication scope}
+ * @return the credentials
+ *
+ * @see #setCredentials(AuthScope, Credentials)
+ */
+ Credentials getCredentials(AuthScope authscope);
+
+ /**
+ * Clears all credentials.
+ */
+ void clear();
+
+}
diff --git a/src/org/apache/http/client/HttpClient.java b/src/org/apache/http/client/HttpClient.java
new file mode 100644
index 0000000..aaa09e0
--- /dev/null
+++ b/src/org/apache/http/client/HttpClient.java
@@ -0,0 +1,249 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/HttpClient.java $
+ * $Revision: 676020 $
+ * $Date: 2008-07-11 09:38:49 -0700 (Fri, 11 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.io.IOException;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+
+/**
+ * Interface for an HTTP client.
+ * HTTP clients encapsulate a smorgasbord of objects required to
+ * execute HTTP requests while handling cookies, authentication,
+ * connection management, and other features.
+ * Thread safety of HTTP clients depends on the implementation
+ * and configuration of the specific client.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 676020 $
+ *
+ * @since 4.0
+ */
+public interface HttpClient {
+
+
+ /**
+ * Obtains the parameters for this client.
+ * These parameters will become defaults for all requests being
+ * executed with this client, and for the parameters of
+ * dependent objects in this client.
+ *
+ * @return the default parameters
+ */
+ HttpParams getParams()
+ ;
+
+
+ /**
+ * Obtains the connection manager used by this client.
+ *
+ * @return the connection manager
+ */
+ ClientConnectionManager getConnectionManager()
+ ;
+
+ /**
+ * Executes a request using the default context.
+ *
+ * @param request the request to execute
+ *
+ * @return the response to the request. This is always a final response,
+ * never an intermediate response with an 1xx status code.
+ * Whether redirects or authentication challenges will be returned
+ * or handled automatically depends on the implementation and
+ * configuration of this client.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ HttpResponse execute(HttpUriRequest request)
+ throws IOException, ClientProtocolException
+ ;
+
+
+ /**
+ * Executes a request using the given context.
+ * The route to the target will be determined by the HTTP client.
+ *
+ * @param request the request to execute
+ * @param context the context to use for the execution, or
+ * <code>null</code> to use the default context
+ *
+ * @return the response to the request. This is always a final response,
+ * never an intermediate response with an 1xx status code.
+ * Whether redirects or authentication challenges will be returned
+ * or handled automatically depends on the implementation and
+ * configuration of this client.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ HttpResponse execute(HttpUriRequest request, HttpContext context)
+ throws IOException, ClientProtocolException
+ ;
+
+
+ /**
+ * Executes a request to the target using the default context.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ *
+ * @return the response to the request. This is always a final response,
+ * never an intermediate response with an 1xx status code.
+ * Whether redirects or authentication challenges will be returned
+ * or handled automatically depends on the implementation and
+ * configuration of this client.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ HttpResponse execute(HttpHost target, HttpRequest request)
+ throws IOException, ClientProtocolException
+ ;
+
+ /**
+ * Executes a request to the target using the given context.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ * @param context the context to use for the execution, or
+ * <code>null</code> to use the default context
+ *
+ * @return the response to the request. This is always a final response,
+ * never an intermediate response with an 1xx status code.
+ * Whether redirects or authentication challenges will be returned
+ * or handled automatically depends on the implementation and
+ * configuration of this client.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ HttpResponse execute(HttpHost target, HttpRequest request,
+ HttpContext context)
+ throws IOException, ClientProtocolException
+ ;
+
+ /**
+ * Executes a request using the default context and processes the
+ * response using the given response handler.
+ *
+ * @param request the request to execute
+ * @param responseHandler the response handler
+ *
+ * @return the response object as generated by the response handler.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ <T> T execute(
+ HttpUriRequest request,
+ ResponseHandler<? extends T> responseHandler)
+ throws IOException, ClientProtocolException
+ ;
+
+ /**
+ * Executes a request using the given context and processes the
+ * response using the given response handler.
+ *
+ * @param request the request to execute
+ * @param responseHandler the response handler
+ *
+ * @return the response object as generated by the response handler.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ <T> T execute(
+ HttpUriRequest request,
+ ResponseHandler<? extends T> responseHandler,
+ HttpContext context)
+ throws IOException, ClientProtocolException
+ ;
+
+ /**
+ * Executes a request to the target using the default context and
+ * processes the response using the given response handler.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ * @param responseHandler the response handler
+ *
+ * @return the response object as generated by the response handler.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ <T> T execute(
+ HttpHost target,
+ HttpRequest request,
+ ResponseHandler<? extends T> responseHandler)
+ throws IOException, ClientProtocolException
+ ;
+
+ /**
+ * Executes a request to the target using the given context and
+ * processes the response using the given response handler.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ * @param responseHandler the response handler
+ * @param context the context to use for the execution, or
+ * <code>null</code> to use the default context
+ *
+ * @return the response object as generated by the response handler.
+ * @throws IOException in case of a problem or the connection was aborted
+ * @throws ClientProtocolException in case of an http protocol error
+ */
+ <T> T execute(
+ HttpHost target,
+ HttpRequest request,
+ ResponseHandler<? extends T> responseHandler,
+ HttpContext context)
+ throws IOException, ClientProtocolException
+ ;
+
+} // interface HttpClient
diff --git a/src/org/apache/http/client/HttpRequestRetryHandler.java b/src/org/apache/http/client/HttpRequestRetryHandler.java
new file mode 100644
index 0000000..9ef8ef9
--- /dev/null
+++ b/src/org/apache/http/client/HttpRequestRetryHandler.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java $
+ * $Revision: 535610 $
+ * $Date: 2007-05-06 06:28:13 -0700 (Sun, 06 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.io.IOException;
+
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * A handler for determining if an HttpRequest should be retried after a
+ * recoverable exception during execution.
+ *
+ * <p>
+ * Classes implementing this interface must synchronize access to shared
+ * data as methods of this interfrace may be executed from multiple threads
+ * </p>
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public interface HttpRequestRetryHandler {
+
+ /**
+ * Determines if a method should be retried after an IOException
+ * occurs during execution.
+ *
+ * @param exception the exception that occurred
+ * @param executionCount the number of times this method has been
+ * unsuccessfully executed
+ * @param context the context for the request execution
+ *
+ * @return <code>true</code> if the method should be retried, <code>false</code>
+ * otherwise
+ */
+ boolean retryRequest(IOException exception, int executionCount, HttpContext context);
+
+}
diff --git a/src/org/apache/http/client/HttpResponseException.java b/src/org/apache/http/client/HttpResponseException.java
new file mode 100644
index 0000000..4d8de91
--- /dev/null
+++ b/src/org/apache/http/client/HttpResponseException.java
@@ -0,0 +1,51 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/HttpResponseException.java $
+ * $Revision: 672425 $
+ * $Date: 2008-06-27 16:33:05 -0700 (Fri, 27 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+/**
+ * Signals a non 2xx HTTP response.
+ */
+public class HttpResponseException extends ClientProtocolException {
+
+ private static final long serialVersionUID = -7186627969477257933L;
+
+ private final int statusCode;
+
+ public HttpResponseException(int statusCode, final String s) {
+ super(s);
+ this.statusCode = statusCode;
+ }
+
+ public int getStatusCode() {
+ return this.statusCode;
+ }
+
+}
diff --git a/src/org/apache/http/client/NonRepeatableRequestException.java b/src/org/apache/http/client/NonRepeatableRequestException.java
new file mode 100644
index 0000000..13ff4d1
--- /dev/null
+++ b/src/org/apache/http/client/NonRepeatableRequestException.java
@@ -0,0 +1,63 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/NonRepeatableRequestException.java $
+ * $Revision: 664326 $
+ * $Date: 2008-06-07 04:48:27 -0700 (Sat, 07 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import org.apache.http.ProtocolException;
+
+/**
+ * Signals failure to retry the request due to non-repeatable request
+ * entity.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class NonRepeatableRequestException extends ProtocolException {
+
+ private static final long serialVersionUID = 82685265288806048L;
+
+ /**
+ * Creates a new NonRepeatableEntityException with a <tt>null</tt> detail message.
+ */
+ public NonRepeatableRequestException() {
+ super();
+ }
+
+ /**
+ * Creates a new NonRepeatableEntityException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public NonRepeatableRequestException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/client/RedirectException.java b/src/org/apache/http/client/RedirectException.java
new file mode 100644
index 0000000..82ea9ea
--- /dev/null
+++ b/src/org/apache/http/client/RedirectException.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/RedirectException.java $
+ * $Revision: 664066 $
+ * $Date: 2008-06-06 11:13:18 -0700 (Fri, 06 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import org.apache.http.ProtocolException;
+
+/**
+ * Signals violation of HTTP specification caused by an invalid redirect
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class RedirectException extends ProtocolException {
+
+ private static final long serialVersionUID = 4418824536372559326L;
+
+ /**
+ * Creates a new RedirectException with a <tt>null</tt> detail message.
+ */
+ public RedirectException() {
+ super();
+ }
+
+ /**
+ * Creates a new RedirectException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public RedirectException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new RedirectException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public RedirectException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/client/RedirectHandler.java b/src/org/apache/http/client/RedirectHandler.java
new file mode 100644
index 0000000..a98b4ae
--- /dev/null
+++ b/src/org/apache/http/client/RedirectHandler.java
@@ -0,0 +1,79 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/RedirectHandler.java $
+ * $Revision: 538647 $
+ * $Date: 2007-05-16 09:41:42 -0700 (Wed, 16 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * A handler for determining if an HTTP request should be redirected to
+ * a new location in response to an HTTP response received from the target
+ * server.
+ *
+ * <p>
+ * Classes implementing this interface must synchronize access to shared
+ * data as methods of this interfrace may be executed from multiple threads
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public interface RedirectHandler {
+
+ /**
+ * Determines if a request should be redirected to a new location
+ * given the response from the target server.
+ *
+ * @param response the response received from the target server
+ * @param context the context for the request execution
+ *
+ * @return <code>true</code> if the request should be redirected, <code>false</code>
+ * otherwise
+ */
+ boolean isRedirectRequested(HttpResponse response, HttpContext context);
+
+ /**
+ * Determines the location request is expected to be redirected to
+ * given the response from the target server and the current request
+ * execution context.
+ *
+ * @param response the response received from the target server
+ * @param context the context for the request execution
+ *
+ * @return redirect URI
+ */
+ URI getLocationURI(HttpResponse response, HttpContext context)
+ throws ProtocolException;
+
+}
diff --git a/src/org/apache/http/client/RequestDirector.java b/src/org/apache/http/client/RequestDirector.java
new file mode 100644
index 0000000..924c312
--- /dev/null
+++ b/src/org/apache/http/client/RequestDirector.java
@@ -0,0 +1,92 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/RequestDirector.java $
+ * $Revision: 676020 $
+ * $Date: 2008-07-11 09:38:49 -0700 (Fri, 11 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.io.IOException;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * A client-side request director.
+ * The director decides which steps are necessary to execute a request.
+ * It establishes connections and optionally processes redirects and
+ * authentication challenges. The director may therefore generate and
+ * send a sequence of requests in order to execute one initial request.
+ *
+ * <br/><b>Note:</b>
+ * It is most likely that implementations of this interface will
+ * allocate connections, and return responses that depend on those
+ * connections for reading the response entity. Such connections
+ * MUST be released, but that is out of the scope of a request director.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 676020 $
+ *
+ * @since 4.0
+ */
+public interface RequestDirector {
+
+
+ /**
+ * Executes a request.
+ * <br/><b>Note:</b>
+ * For the time being, a new director is instantiated for each request.
+ * This is the same behavior as for <code>HttpMethodDirector</code>
+ * in HttpClient 3.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ * @param context the context for executing the request
+ *
+ * @return the final response to the request.
+ * This is never an intermediate response with status code 1xx.
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ * or if the connection was aborted
+ */
+ HttpResponse execute(HttpHost target, HttpRequest request,
+ HttpContext context)
+ throws HttpException, IOException
+ ;
+
+} // class ClientRequestDirector
diff --git a/src/org/apache/http/client/ResponseHandler.java b/src/org/apache/http/client/ResponseHandler.java
new file mode 100644
index 0000000..33a3391
--- /dev/null
+++ b/src/org/apache/http/client/ResponseHandler.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/ResponseHandler.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import java.io.IOException;
+
+import org.apache.http.HttpResponse;
+
+/**
+ * Handler that encapsulates the process of generating a response object
+ * from a {@link HttpResponse}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface ResponseHandler<T> {
+
+ /**
+ * Processes an {@link HttpResponse} and returns some value
+ * corresponding to that response.
+ *
+ * @param response The response to process
+ * @return A value determined by the response
+ *
+ * @throws ClientProtocolException in case of an http protocol error
+ * @throws IOException in case of a problem or the connection was aborted
+ */
+ T handleResponse(HttpResponse response) throws ClientProtocolException, IOException;
+
+}
diff --git a/src/org/apache/http/client/UserTokenHandler.java b/src/org/apache/http/client/UserTokenHandler.java
new file mode 100644
index 0000000..f8e55d8
--- /dev/null
+++ b/src/org/apache/http/client/UserTokenHandler.java
@@ -0,0 +1,64 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java $
+ * $Revision: 658759 $
+ * $Date: 2008-05-21 10:06:17 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client;
+
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * A handler for determining if the given execution context is user specific
+ * or not. The token object returned by this handler is expected to uniquely
+ * identify the current user if the context is user specific or to be
+ * <code>null</code> if the context does not contain any resources or details
+ * specific to the current user.
+ * <p/>
+ * The user token will be used to ensure that user specific resouces will not
+ * shared with or reused by other users.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface UserTokenHandler {
+
+ /**
+ * The token object returned by this method is expected to uniquely
+ * identify the current user if the context is user specific or to be
+ * <code>null</code> if it is not.
+ *
+ * @param context the execution context
+ *
+ * @return user token that uniquely identifies the user or
+ * <code>null</null> if the context is not user specific.
+ */
+ Object getUserToken(HttpContext context);
+
+}
diff --git a/src/org/apache/http/client/entity/UrlEncodedFormEntity.java b/src/org/apache/http/client/entity/UrlEncodedFormEntity.java
new file mode 100644
index 0000000..89b9c45
--- /dev/null
+++ b/src/org/apache/http/client/entity/UrlEncodedFormEntity.java
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/entity/UrlEncodedFormEntity.java $
+ * $Revision: 655107 $
+ * $Date: 2008-05-10 08:20:42 -0700 (Sat, 10 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.entity;
+
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * An entity composed of a list of url-encoded pairs.
+ * This is typically useful while sending an HTTP POST request.
+ */
+public class UrlEncodedFormEntity extends StringEntity {
+
+ /**
+ * Constructs a new {@link UrlEncodedFormEntity} with the list
+ * of parameters in the specified encoding.
+ *
+ * @param parameters list of name/value pairs
+ * @param encoding encoding the name/value pairs be encoded with
+ * @throws UnsupportedEncodingException if the encoding isn't supported
+ */
+ public UrlEncodedFormEntity (
+ final List <? extends NameValuePair> parameters,
+ final String encoding) throws UnsupportedEncodingException {
+ super(URLEncodedUtils.format(parameters, encoding),
+ encoding);
+ setContentType(URLEncodedUtils.CONTENT_TYPE);
+ }
+
+ /**
+ * Constructs a new {@link UrlEncodedFormEntity} with the list
+ * of parameters with the default encoding of {@link HTTP#DEFAULT_CONTENT_CHARSET}
+ *
+ * @param parameters list of name/value pairs
+ * @throws UnsupportedEncodingException if the default encoding isn't supported
+ */
+ public UrlEncodedFormEntity (
+ final List <? extends NameValuePair> parameters) throws UnsupportedEncodingException {
+ super(URLEncodedUtils.format(parameters, HTTP.DEFAULT_CONTENT_CHARSET),
+ HTTP.DEFAULT_CONTENT_CHARSET);
+ setContentType(URLEncodedUtils.CONTENT_TYPE);
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/AbortableHttpRequest.java b/src/org/apache/http/client/methods/AbortableHttpRequest.java
new file mode 100644
index 0000000..c402609
--- /dev/null
+++ b/src/org/apache/http/client/methods/AbortableHttpRequest.java
@@ -0,0 +1,91 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/AbortableHttpRequest.java $
+ * $Revision: 639600 $
+ * $Date: 2008-03-21 04:28:15 -0700 (Fri, 21 Mar 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.io.IOException;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ConnectionReleaseTrigger;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+
+/**
+ * Interface representing an HTTP request that can be aborted by shutting
+ * down the underlying HTTP connection.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 639600 $
+ *
+ * @since 4.0
+ */
+public interface AbortableHttpRequest {
+
+ /**
+ * Sets the {@link ClientConnectionRequest} callback that can be
+ * used to abort a long-lived request for a connection.
+ * If the request is already aborted, throws an {@link IOException}.
+ *
+ * @see ClientConnectionManager
+ * @see ThreadSafeClientConnManager
+ */
+ void setConnectionRequest(ClientConnectionRequest connRequest) throws IOException;
+
+ /**
+ * Sets the {@link ConnectionReleaseTrigger} callback that can
+ * be used to abort an active connection.
+ * Typically, this will be the {@link ManagedClientConnection} itself.
+ * If the request is already aborted, throws an {@link IOException}.
+ */
+ void setReleaseTrigger(ConnectionReleaseTrigger releaseTrigger) throws IOException;
+
+ /**
+ * Aborts this http request. Any active execution of this method should
+ * return immediately. If the request has not started, it will abort after
+ * the next execution. Aborting this request will cause all subsequent
+ * executions with this request to fail.
+ *
+ * @see HttpClient#execute(HttpUriRequest)
+ * @see HttpClient#execute(org.apache.http.HttpHost,
+ * org.apache.http.HttpRequest)
+ * @see HttpClient#execute(HttpUriRequest,
+ * org.apache.http.protocol.HttpContext)
+ * @see HttpClient#execute(org.apache.http.HttpHost,
+ * org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext)
+ */
+ void abort();
+
+}
+
diff --git a/src/org/apache/http/client/methods/HttpDelete.java b/src/org/apache/http/client/methods/HttpDelete.java
new file mode 100644
index 0000000..4a0fb77
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpDelete.java
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpDelete.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+/**
+ * HTTP DELETE method
+ * <p>
+ * The HTTP DELETE method is defined in section 9.7 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The DELETE method requests that the origin server delete the resource
+ * identified by the Request-URI. [...] The client cannot
+ * be guaranteed that the operation has been carried out, even if the
+ * status code returned from the origin server indicates that the action
+ * has been completed successfully.
+ * </blockquote>
+ */
+public class HttpDelete extends HttpRequestBase {
+
+ public final static String METHOD_NAME = "DELETE";
+
+
+ public HttpDelete() {
+ super();
+ }
+
+ public HttpDelete(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpDelete(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java b/src/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java
new file mode 100644
index 0000000..8ac6f01
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java
@@ -0,0 +1,81 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.client.utils.CloneUtils;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Basic implementation of an HTTP request that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 674186 $
+ *
+ * @since 4.0
+ */
+public abstract class HttpEntityEnclosingRequestBase
+ extends HttpRequestBase implements HttpEntityEnclosingRequest {
+
+ private HttpEntity entity;
+
+ public HttpEntityEnclosingRequestBase() {
+ super();
+ }
+
+ public HttpEntity getEntity() {
+ return this.entity;
+ }
+
+ public void setEntity(final HttpEntity entity) {
+ this.entity = entity;
+ }
+
+ public boolean expectContinue() {
+ Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
+ return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ HttpEntityEnclosingRequestBase clone =
+ (HttpEntityEnclosingRequestBase) super.clone();
+ if (this.entity != null) {
+ clone.entity = (HttpEntity) CloneUtils.clone(this.entity);
+ }
+ return clone;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpGet.java b/src/org/apache/http/client/methods/HttpGet.java
new file mode 100644
index 0000000..2908f1d
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpGet.java
@@ -0,0 +1,83 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpGet.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+/**
+ * HTTP GET method.
+ * <p>
+ * The HTTP GET method is defined in section 9.3 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The GET method means retrieve whatever information (in the form of an
+ * entity) is identified by the Request-URI. If the Request-URI refers
+ * to a data-producing process, it is the produced data which shall be
+ * returned as the entity in the response and not the source text of the
+ * process, unless that text happens to be the output of the process.
+ * </blockquote>
+ * </p>
+ * <p>
+ * GetMethods will follow redirect requests from the http server by default.
+ * This behavour can be disabled by calling setFollowRedirects(false).</p>
+ *
+ * @version $Revision: 664505 $
+ *
+ * @since 4.0
+ */
+public class HttpGet extends HttpRequestBase {
+
+ public final static String METHOD_NAME = "GET";
+
+ public HttpGet() {
+ super();
+ }
+
+ public HttpGet(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpGet(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpHead.java b/src/org/apache/http/client/methods/HttpHead.java
new file mode 100644
index 0000000..29e58a3
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpHead.java
@@ -0,0 +1,83 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpHead.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+/**
+ * HTTP HEAD method.
+ * <p>
+ * The HTTP HEAD method is defined in section 9.4 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The HEAD method is identical to GET except that the server MUST NOT
+ * return a message-body in the response. The metainformation contained
+ * in the HTTP headers in response to a HEAD request SHOULD be identical
+ * to the information sent in response to a GET request. This method can
+ * be used for obtaining metainformation about the entity implied by the
+ * request without transferring the entity-body itself. This method is
+ * often used for testing hypertext links for validity, accessibility,
+ * and recent modification.
+ * </blockquote>
+ * </p>
+ *
+ * @version $Revision: 664505 $
+ *
+ * @since 4.0
+ */
+public class HttpHead extends HttpRequestBase {
+
+ public final static String METHOD_NAME = "HEAD";
+
+ public HttpHead() {
+ super();
+ }
+
+ public HttpHead(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpHead(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpOptions.java b/src/org/apache/http/client/methods/HttpOptions.java
new file mode 100644
index 0000000..3758360
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpOptions.java
@@ -0,0 +1,105 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpOptions.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpResponse;
+
+/**
+ * HTTP OPTIONS method.
+ * <p>
+ * The HTTP OPTIONS method is defined in section 9.2 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The OPTIONS method represents a request for information about the
+ * communication options available on the request/response chain
+ * identified by the Request-URI. This method allows the client to
+ * determine the options and/or requirements associated with a resource,
+ * or the capabilities of a server, without implying a resource action
+ * or initiating a resource retrieval.
+ * </blockquote>
+ * </p>
+ *
+ * @version $Revision: 664505 $
+ *
+ * @since 4.0
+ */
+public class HttpOptions extends HttpRequestBase {
+
+ public final static String METHOD_NAME = "OPTIONS";
+
+ public HttpOptions() {
+ super();
+ }
+
+ public HttpOptions(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpOptions(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+ public Set<String> getAllowedMethods(final HttpResponse response) {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+
+ HeaderIterator it = response.headerIterator("Allow");
+ Set<String> methods = new HashSet<String>();
+ while (it.hasNext()) {
+ Header header = it.nextHeader();
+ HeaderElement[] elements = header.getElements();
+ for (HeaderElement element : elements) {
+ methods.add(element.getName());
+ }
+ }
+ return methods;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpPost.java b/src/org/apache/http/client/methods/HttpPost.java
new file mode 100644
index 0000000..bc58803
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpPost.java
@@ -0,0 +1,87 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpPost.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+/**
+ * HTTP POST method.
+ * <p>
+ * The HTTP POST method is defined in section 9.5 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The POST method is used to request that the origin server accept the entity
+ * enclosed in the request as a new subordinate of the resource identified by
+ * the Request-URI in the Request-Line. POST is designed to allow a uniform
+ * method to cover the following functions:
+ * <ul>
+ * <li>Annotation of existing resources</li>
+ * <li>Posting a message to a bulletin board, newsgroup, mailing list, or
+ * similar group of articles</li>
+ * <li>Providing a block of data, such as the result of submitting a form,
+ * to a data-handling process</li>
+ * <li>Extending a database through an append operation</li>
+ * </ul>
+ * </blockquote>
+ * </p>
+ *
+ * @version $Revision: 664505 $
+ *
+ * @since 4.0
+ */
+public class HttpPost extends HttpEntityEnclosingRequestBase {
+
+ public final static String METHOD_NAME = "POST";
+
+ public HttpPost() {
+ super();
+ }
+
+ public HttpPost(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpPost(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpPut.java b/src/org/apache/http/client/methods/HttpPut.java
new file mode 100644
index 0000000..5b50135
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpPut.java
@@ -0,0 +1,79 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpPut.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+/**
+ * HTTP PUT method.
+ * <p>
+ * The HTTP PUT method is defined in section 9.6 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The PUT method requests that the enclosed entity be stored under the
+ * supplied Request-URI. If the Request-URI refers to an already
+ * existing resource, the enclosed entity SHOULD be considered as a
+ * modified version of the one residing on the origin server.
+ * </blockquote>
+ * </p>
+ *
+ * @version $Revision: 664505 $
+ *
+ * @since 4.0
+ */
+public class HttpPut extends HttpEntityEnclosingRequestBase {
+
+ public final static String METHOD_NAME = "PUT";
+
+ public HttpPut() {
+ super();
+ }
+
+ public HttpPut(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpPut(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpRequestBase.java b/src/org/apache/http/client/methods/HttpRequestBase.java
new file mode 100644
index 0000000..8938ea0
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpRequestBase.java
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpRequestBase.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.client.utils.CloneUtils;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ConnectionReleaseTrigger;
+import org.apache.http.message.AbstractHttpMessage;
+import org.apache.http.message.BasicRequestLine;
+import org.apache.http.message.HeaderGroup;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+
+/**
+ * Basic implementation of an HTTP request that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 674186 $
+ *
+ * @since 4.0
+ */
+public abstract class HttpRequestBase extends AbstractHttpMessage
+ implements HttpUriRequest, AbortableHttpRequest, Cloneable {
+
+ private Lock abortLock;
+
+ private boolean aborted;
+
+ private URI uri;
+ private ClientConnectionRequest connRequest;
+ private ConnectionReleaseTrigger releaseTrigger;
+
+ public HttpRequestBase() {
+ super();
+ this.abortLock = new ReentrantLock();
+ }
+
+ public abstract String getMethod();
+
+ public ProtocolVersion getProtocolVersion() {
+ return HttpProtocolParams.getVersion(getParams());
+ }
+
+ public URI getURI() {
+ return this.uri;
+ }
+
+ public RequestLine getRequestLine() {
+ String method = getMethod();
+ ProtocolVersion ver = getProtocolVersion();
+ URI uri = getURI();
+ String uritext = null;
+ if (uri != null) {
+ uritext = uri.toASCIIString();
+ }
+ if (uritext == null || uritext.length() == 0) {
+ uritext = "/";
+ }
+ return new BasicRequestLine(method, uritext, ver);
+ }
+
+ public void setURI(final URI uri) {
+ this.uri = uri;
+ }
+
+ public void setConnectionRequest(final ClientConnectionRequest connRequest)
+ throws IOException {
+ this.abortLock.lock();
+ try {
+ if (this.aborted) {
+ throw new IOException("Request already aborted");
+ }
+
+ this.releaseTrigger = null;
+ this.connRequest = connRequest;
+ } finally {
+ this.abortLock.unlock();
+ }
+ }
+
+ public void setReleaseTrigger(final ConnectionReleaseTrigger releaseTrigger)
+ throws IOException {
+ this.abortLock.lock();
+ try {
+ if (this.aborted) {
+ throw new IOException("Request already aborted");
+ }
+
+ this.connRequest = null;
+ this.releaseTrigger = releaseTrigger;
+ } finally {
+ this.abortLock.unlock();
+ }
+ }
+
+ public void abort() {
+ ClientConnectionRequest localRequest;
+ ConnectionReleaseTrigger localTrigger;
+
+ this.abortLock.lock();
+ try {
+ if (this.aborted) {
+ return;
+ }
+ this.aborted = true;
+
+ localRequest = connRequest;
+ localTrigger = releaseTrigger;
+ } finally {
+ this.abortLock.unlock();
+ }
+
+ // Trigger the callbacks outside of the lock, to prevent
+ // deadlocks in the scenario where the callbacks have
+ // their own locks that may be used while calling
+ // setReleaseTrigger or setConnectionRequest.
+ if (localRequest != null) {
+ localRequest.abortRequest();
+ }
+ if (localTrigger != null) {
+ try {
+ localTrigger.abortConnection();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ }
+
+ public boolean isAborted() {
+ return this.aborted;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ HttpRequestBase clone = (HttpRequestBase) super.clone();
+ clone.abortLock = new ReentrantLock();
+ clone.aborted = false;
+ clone.releaseTrigger = null;
+ clone.connRequest = null;
+ clone.headergroup = (HeaderGroup) CloneUtils.clone(this.headergroup);
+ clone.params = (HttpParams) CloneUtils.clone(this.params);
+ return clone;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpTrace.java b/src/org/apache/http/client/methods/HttpTrace.java
new file mode 100644
index 0000000..94f18ff
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpTrace.java
@@ -0,0 +1,82 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpTrace.java $
+ * $Revision: 664505 $
+ * $Date: 2008-06-08 06:21:20 -0700 (Sun, 08 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+/**
+ * HTTP TRACE method.
+ * <p>
+ * The HTTP TRACE method is defined in section 9.6 of
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>
+ * The TRACE method is used to invoke a remote, application-layer loop-
+ * back of the request message. The final recipient of the request
+ * SHOULD reflect the message received back to the client as the
+ * entity-body of a 200 (OK) response. The final recipient is either the
+ * origin server or the first proxy or gateway to receive a Max-Forwards
+ * value of zero (0) in the request (see section 14.31). A TRACE request
+ * MUST NOT include an entity.
+ * </blockquote>
+ * </p>
+ *
+ * @version $Revision: 664505 $
+ *
+ * @since 4.0
+ */
+public class HttpTrace extends HttpRequestBase {
+
+ public final static String METHOD_NAME = "TRACE";
+
+ public HttpTrace() {
+ super();
+ }
+
+ public HttpTrace(final URI uri) {
+ super();
+ setURI(uri);
+ }
+
+ /**
+ * @throws IllegalArgumentException if the uri is invalid.
+ */
+ public HttpTrace(final String uri) {
+ super();
+ setURI(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return METHOD_NAME;
+ }
+
+}
diff --git a/src/org/apache/http/client/methods/HttpUriRequest.java b/src/org/apache/http/client/methods/HttpUriRequest.java
new file mode 100644
index 0000000..56d064a
--- /dev/null
+++ b/src/org/apache/http/client/methods/HttpUriRequest.java
@@ -0,0 +1,80 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/HttpUriRequest.java $
+ * $Revision: 659191 $
+ * $Date: 2008-05-22 11:26:53 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpRequest;
+
+/**
+ * Extended version of the {@link HttpRequest} interface that provides
+ * convenience methods to access request properties such as request URI
+ * and method type.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 659191 $
+ *
+ * @since 4.0
+ */
+public interface HttpUriRequest extends HttpRequest {
+
+ /**
+ * Returns the HTTP method this request uses, such as <code>GET</code>,
+ * <code>PUT</code>, <code>POST</code>, or other.
+ */
+ String getMethod();
+
+ /**
+ * Returns the URI this request uses, such as
+ * <code>http://example.org/path/to/file</code>.
+ */
+ URI getURI();
+
+ /**
+ * Aborts execution of the request.
+ *
+ * @throws UnsupportedOperationException if the abort operation
+ * is not supported / cannot be implemented.
+ */
+ void abort() throws UnsupportedOperationException;
+
+ /**
+ * Tests if the request execution has been aborted.
+ *
+ * @return <code>true</code> if the request execution has been aborted,
+ * <code>false</code> otherwise.
+ */
+ boolean isAborted();
+
+}
diff --git a/src/org/apache/http/client/methods/package.html b/src/org/apache/http/client/methods/package.html
new file mode 100644
index 0000000..c2a602a
--- /dev/null
+++ b/src/org/apache/http/client/methods/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/methods/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Request implementations for the various HTTP methods like GET and POST.
+
+</body>
+</html>
diff --git a/src/org/apache/http/client/package.html b/src/org/apache/http/client/package.html
new file mode 100644
index 0000000..64c7287
--- /dev/null
+++ b/src/org/apache/http/client/package.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The API for client-side HTTP communication and
+entry point to the <i>HttpClient</i> module.
+
+</body>
+</html>
diff --git a/src/org/apache/http/client/params/AllClientPNames.java b/src/org/apache/http/client/params/AllClientPNames.java
new file mode 100644
index 0000000..e55bca7
--- /dev/null
+++ b/src/org/apache/http/client/params/AllClientPNames.java
@@ -0,0 +1,65 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/AllClientPNames.java $
+ * $Revision: 576078 $
+ * $Date: 2007-09-16 04:50:41 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.params;
+
+
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.auth.params.AuthPNames;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.conn.params.ConnManagerPNames;
+import org.apache.http.conn.params.ConnConnectionPNames;
+import org.apache.http.conn.params.ConnRoutePNames;
+
+
+/**
+ * Collected parameter names for the HttpClient module.
+ * This interface combines the parameter definitions of the HttpClient
+ * module and all dependency modules or informational units.
+ * It does not define additional parameter names, but references
+ * other interfaces defining parameter names.
+ * <br/>
+ * This interface is meant as a navigation aid for developers.
+ * When referring to parameter names, you should use the interfaces
+ * in which the respective constants are actually defined.
+ *
+ * @version $Revision: 576078 $
+ *
+ * @since 4.0
+ */
+public interface AllClientPNames extends
+ CoreConnectionPNames, CoreProtocolPNames,
+ ClientPNames, AuthPNames, CookieSpecPNames,
+ ConnConnectionPNames, ConnManagerPNames, ConnRoutePNames {
+
+ // no additional definitions
+}
+
diff --git a/src/org/apache/http/client/params/AuthPolicy.java b/src/org/apache/http/client/params/AuthPolicy.java
new file mode 100644
index 0000000..5bcdd38
--- /dev/null
+++ b/src/org/apache/http/client/params/AuthPolicy.java
@@ -0,0 +1,58 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/AuthPolicy.java $
+ * $Revision: 534839 $
+ * $Date: 2007-05-03 06:03:41 -0700 (Thu, 03 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.params;
+
+public final class AuthPolicy {
+
+ private AuthPolicy() {
+ super();
+ }
+
+ /**
+ * The NTLM scheme is a proprietary Microsoft Windows Authentication
+ * protocol (considered to be the most secure among currently supported
+ * authentication schemes).
+ */
+ public static final String NTLM = "NTLM";
+
+ /**
+ * Digest authentication scheme as defined in RFC2617.
+ */
+ public static final String DIGEST = "Digest";
+
+ /**
+ * Basic authentication scheme as defined in RFC2617 (considered inherently
+ * insecure, but most widely supported)
+ */
+ public static final String BASIC = "Basic";
+
+}
diff --git a/src/org/apache/http/client/params/ClientPNames.java b/src/org/apache/http/client/params/ClientPNames.java
new file mode 100644
index 0000000..f98eeb7
--- /dev/null
+++ b/src/org/apache/http/client/params/ClientPNames.java
@@ -0,0 +1,139 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/ClientPNames.java $
+ * $Revision: 659595 $
+ * $Date: 2008-05-23 09:47:14 -0700 (Fri, 23 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.params;
+
+
+/**
+ * Parameter names for the HttpClient module.
+ * This does not include parameters for informational units
+ * HttpAuth, HttpCookie, or HttpConn.
+ *
+ * @version $Revision: 659595 $
+ *
+ * @since 4.0
+ */
+public interface ClientPNames {
+
+ /**
+ * Defines the class name of the default {@link org.apache.http.conn.ClientConnectionManager}
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * </p>
+ */
+ public static final String CONNECTION_MANAGER_FACTORY_CLASS_NAME = "http.connection-manager.factory-class-name";
+
+ /**
+ * Defines the factory to create a default {@link org.apache.http.conn.ClientConnectionManager}.
+ * <p>
+ * This parameters expects a value of type {@link org.apache.http.conn.ClientConnectionManagerFactory}.
+ * </p>
+ */
+ public static final String CONNECTION_MANAGER_FACTORY = "http.connection-manager.factory-object";
+
+ /**
+ * Defines whether redirects should be handled automatically
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String HANDLE_REDIRECTS = "http.protocol.handle-redirects";
+
+ /**
+ * Defines whether relative redirects should be rejected.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String REJECT_RELATIVE_REDIRECT = "http.protocol.reject-relative-redirect";
+
+ /**
+ * Defines the maximum number of redirects to be followed.
+ * The limit on number of redirects is intended to prevent infinite loops.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String MAX_REDIRECTS = "http.protocol.max-redirects";
+
+ /**
+ * Defines whether circular redirects (redirects to the same location) should be allowed.
+ * The HTTP spec is not sufficiently clear whether circular redirects are permitted,
+ * therefore optionally they can be enabled
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String ALLOW_CIRCULAR_REDIRECTS = "http.protocol.allow-circular-redirects";
+
+ /**
+ * Defines whether authentication should be handled automatically.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String HANDLE_AUTHENTICATION = "http.protocol.handle-authentication";
+
+ /**
+ * Defines the name of the cookie specification to be used for HTTP state management.
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * </p>
+ */
+ public static final String COOKIE_POLICY = "http.protocol.cookie-policy";
+
+ /**
+ * Defines the virtual host name.
+ * <p>
+ * This parameter expects a value of type {@link org.apache.http.HttpHost}.
+ * </p>
+ */
+ public static final String VIRTUAL_HOST = "http.virtual-host";
+
+ /**
+ * Defines the request headers to be sent per default with each request.
+ * <p>
+ * This parameter expects a value of type {@link java.util.Collection}. The
+ * collection is expected to contain {@link org.apache.http.Header}s.
+ * </p>
+ */
+ public static final String DEFAULT_HEADERS = "http.default-headers";
+
+ /**
+ * Defines the default host. The default value will be used if the target host is
+ * not explicitly specified in the request URI.
+ * <p>
+ * This parameter expects a value of type {@link org.apache.http.HttpHost}.
+ * </p>
+ */
+ public static final String DEFAULT_HOST = "http.default-host";
+
+}
+
diff --git a/src/org/apache/http/client/params/ClientParamBean.java b/src/org/apache/http/client/params/ClientParamBean.java
new file mode 100644
index 0000000..76431a7
--- /dev/null
+++ b/src/org/apache/http/client/params/ClientParamBean.java
@@ -0,0 +1,92 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/ClientParamBean.java $
+ * $Revision: 659595 $
+ * $Date: 2008-05-23 09:47:14 -0700 (Fri, 23 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.params;
+
+import java.util.Collection;
+
+import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.conn.ClientConnectionManagerFactory;
+import org.apache.http.params.HttpAbstractParamBean;
+import org.apache.http.params.HttpParams;
+
+public class ClientParamBean extends HttpAbstractParamBean {
+
+ public ClientParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ public void setConnectionManagerFactoryClassName (final String factory) {
+ params.setParameter(ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME, factory);
+ }
+
+ public void setConnectionManagerFactory(ClientConnectionManagerFactory factory) {
+ params.setParameter(ClientPNames.CONNECTION_MANAGER_FACTORY, factory);
+ }
+
+ public void setHandleRedirects (final boolean handle) {
+ params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, handle);
+ }
+
+ public void setRejectRelativeRedirect (final boolean reject) {
+ params.setBooleanParameter(ClientPNames.REJECT_RELATIVE_REDIRECT, reject);
+ }
+
+ public void setMaxRedirects (final int maxRedirects) {
+ params.setIntParameter(ClientPNames.MAX_REDIRECTS, maxRedirects);
+ }
+
+ public void setAllowCircularRedirects (final boolean allow) {
+ params.setBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, allow);
+ }
+
+ public void setHandleAuthentication (final boolean handle) {
+ params.setBooleanParameter(ClientPNames.HANDLE_AUTHENTICATION, handle);
+ }
+
+ public void setCookiePolicy (final String policy) {
+ params.setParameter(ClientPNames.COOKIE_POLICY, policy);
+ }
+
+ public void setVirtualHost (final HttpHost host) {
+ params.setParameter(ClientPNames.VIRTUAL_HOST, host);
+ }
+
+ public void setDefaultHeaders (final Collection <Header> headers) {
+ params.setParameter(ClientPNames.DEFAULT_HEADERS, headers);
+ }
+
+ public void setDefaultHost (final HttpHost host) {
+ params.setParameter(ClientPNames.DEFAULT_HOST, host);
+ }
+
+}
diff --git a/src/org/apache/http/client/params/CookiePolicy.java b/src/org/apache/http/client/params/CookiePolicy.java
new file mode 100644
index 0000000..04a131d
--- /dev/null
+++ b/src/org/apache/http/client/params/CookiePolicy.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/CookiePolicy.java $
+ * $Revision: 613865 $
+ * $Date: 2008-01-21 04:04:30 -0800 (Mon, 21 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.params;
+
+public final class CookiePolicy {
+
+ /**
+ * The policy that provides high degree of compatibilty
+ * with common cookie management of popular HTTP agents.
+ */
+ public static final String BROWSER_COMPATIBILITY = "compatibility";
+
+ /**
+ * The Netscape cookie draft compliant policy.
+ */
+ public static final String NETSCAPE = "netscape";
+
+ /**
+ * The RFC 2109 compliant policy.
+ */
+ public static final String RFC_2109 = "rfc2109";
+
+ /**
+ * The RFC 2965 compliant policy.
+ */
+ public static final String RFC_2965 = "rfc2965";
+
+ /**
+ * The default 'best match' policy.
+ */
+ public static final String BEST_MATCH = "best-match";
+
+ private CookiePolicy() {
+ super();
+ }
+
+}
diff --git a/src/org/apache/http/client/params/HttpClientParams.java b/src/org/apache/http/client/params/HttpClientParams.java
new file mode 100644
index 0000000..c21e2b0
--- /dev/null
+++ b/src/org/apache/http/client/params/HttpClientParams.java
@@ -0,0 +1,101 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/HttpClientParams.java $
+ * $Revision: 659595 $
+ * $Date: 2008-05-23 09:47:14 -0700 (Fri, 23 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.params;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ * An adaptor for accessing HTTP client parameters in {@link HttpParams}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 659595 $
+ *
+ * @since 4.0
+ */
+public class HttpClientParams {
+
+ private HttpClientParams() {
+ super();
+ }
+
+ public static boolean isRedirecting(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (ClientPNames.HANDLE_REDIRECTS, true);
+ }
+
+ public static void setRedirecting(final HttpParams params, boolean value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter
+ (ClientPNames.HANDLE_REDIRECTS, value);
+ }
+
+ public static boolean isAuthenticating(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (ClientPNames.HANDLE_AUTHENTICATION, true);
+ }
+
+ public static void setAuthenticating(final HttpParams params, boolean value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter
+ (ClientPNames.HANDLE_AUTHENTICATION, value);
+ }
+
+ public static String getCookiePolicy(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ String cookiePolicy = (String)
+ params.getParameter(ClientPNames.COOKIE_POLICY);
+ if (cookiePolicy == null) {
+ return CookiePolicy.BEST_MATCH;
+ }
+ return cookiePolicy;
+ }
+
+ public static void setCookiePolicy(final HttpParams params, final String cookiePolicy) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setParameter(ClientPNames.COOKIE_POLICY, cookiePolicy);
+ }
+
+}
diff --git a/src/org/apache/http/client/params/package.html b/src/org/apache/http/client/params/package.html
new file mode 100644
index 0000000..b66cdfb
--- /dev/null
+++ b/src/org/apache/http/client/params/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/params/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Parameters for configuring <i>HttpClient</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/client/protocol/ClientContext.java b/src/org/apache/http/client/protocol/ClientContext.java
new file mode 100644
index 0000000..1859f9e
--- /dev/null
+++ b/src/org/apache/http/client/protocol/ClientContext.java
@@ -0,0 +1,52 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContext.java $
+ * $Revision: 658759 $
+ * $Date: 2008-05-21 10:06:17 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+
+/**
+ * {@link org.apache.http.protocol.HttpContext Context}
+ * attribute names for client.
+ */
+public interface ClientContext {
+
+ public static final String COOKIESPEC_REGISTRY = "http.cookiespec-registry";
+ public static final String AUTHSCHEME_REGISTRY = "http.authscheme-registry";
+ public static final String COOKIE_STORE = "http.cookie-store";
+ public static final String COOKIE_SPEC = "http.cookie-spec";
+ public static final String COOKIE_ORIGIN = "http.cookie-origin";
+ public static final String CREDS_PROVIDER = "http.auth.credentials-provider";
+ public static final String TARGET_AUTH_STATE = "http.auth.target-scope";
+ public static final String PROXY_AUTH_STATE = "http.auth.proxy-scope";
+ public static final String AUTH_SCHEME_PREF = "http.auth.scheme-pref";
+ public static final String USER_TOKEN = "http.user-token";
+
+}
diff --git a/src/org/apache/http/client/protocol/ClientContextConfigurer.java b/src/org/apache/http/client/protocol/ClientContextConfigurer.java
new file mode 100644
index 0000000..f2ced63
--- /dev/null
+++ b/src/org/apache/http/client/protocol/ClientContextConfigurer.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContextConfigurer.java $
+ * $Revision: 654886 $
+ * $Date: 2008-05-09 10:06:12 -0700 (Fri, 09 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+import java.util.List;
+
+import org.apache.http.auth.AuthSchemeRegistry;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.cookie.CookieSpecRegistry;
+import org.apache.http.protocol.HttpContext;
+
+public class ClientContextConfigurer implements ClientContext {
+
+ private final HttpContext context;
+
+ public ClientContextConfigurer (final HttpContext context) {
+ if (context == null)
+ throw new IllegalArgumentException("HTTP context may not be null");
+ this.context = context;
+ }
+
+ public void setCookieSpecRegistry(final CookieSpecRegistry registry) {
+ this.context.setAttribute(COOKIESPEC_REGISTRY, registry);
+ }
+
+ public void setAuthSchemeRegistry(final AuthSchemeRegistry registry) {
+ this.context.setAttribute(AUTHSCHEME_REGISTRY, registry);
+ }
+
+ public void setCookieStore(final CookieStore store) {
+ this.context.setAttribute(COOKIE_STORE, store);
+ }
+
+ public void setCredentialsProvider(final CredentialsProvider provider) {
+ this.context.setAttribute(CREDS_PROVIDER, provider);
+ }
+
+ public void setAuthSchemePref(final List<String> list) {
+ this.context.setAttribute(AUTH_SCHEME_PREF, list);
+ }
+
+}
diff --git a/src/org/apache/http/client/protocol/RequestAddCookies.java b/src/org/apache/http/client/protocol/RequestAddCookies.java
new file mode 100644
index 0000000..0de8c40
--- /dev/null
+++ b/src/org/apache/http/client/protocol/RequestAddCookies.java
@@ -0,0 +1,192 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.ProtocolException;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.params.HttpClientParams;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecRegistry;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.ExecutionContext;
+
+/**
+ * Request interceptor that matches cookies available in the current
+ * {@link CookieStore} to the request being executed and generates
+ * corresponding cookierequest headers.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 673450 $
+ *
+ * @since 4.0
+ */
+public class RequestAddCookies implements HttpRequestInterceptor {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ public RequestAddCookies() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ // Obtain cookie store
+ CookieStore cookieStore = (CookieStore) context.getAttribute(
+ ClientContext.COOKIE_STORE);
+ if (cookieStore == null) {
+ this.log.info("Cookie store not available in HTTP context");
+ return;
+ }
+
+ // Obtain the registry of cookie specs
+ CookieSpecRegistry registry= (CookieSpecRegistry) context.getAttribute(
+ ClientContext.COOKIESPEC_REGISTRY);
+ if (registry == null) {
+ this.log.info("CookieSpec registry not available in HTTP context");
+ return;
+ }
+
+ // Obtain the target host (required)
+ HttpHost targetHost = (HttpHost) context.getAttribute(
+ ExecutionContext.HTTP_TARGET_HOST);
+ if (targetHost == null) {
+ throw new IllegalStateException("Target host not specified in HTTP context");
+ }
+
+ // Obtain the client connection (required)
+ ManagedClientConnection conn = (ManagedClientConnection) context.getAttribute(
+ ExecutionContext.HTTP_CONNECTION);
+ if (conn == null) {
+ throw new IllegalStateException("Client connection not specified in HTTP context");
+ }
+
+ String policy = HttpClientParams.getCookiePolicy(request.getParams());
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("CookieSpec selected: " + policy);
+ }
+
+ URI requestURI;
+ if (request instanceof HttpUriRequest) {
+ requestURI = ((HttpUriRequest) request).getURI();
+ } else {
+ try {
+ requestURI = new URI(request.getRequestLine().getUri());
+ } catch (URISyntaxException ex) {
+ throw new ProtocolException("Invalid request URI: " +
+ request.getRequestLine().getUri(), ex);
+ }
+ }
+
+ String hostName = targetHost.getHostName();
+ int port = targetHost.getPort();
+ if (port < 0) {
+ port = conn.getRemotePort();
+ }
+
+ CookieOrigin cookieOrigin = new CookieOrigin(
+ hostName,
+ port,
+ requestURI.getPath(),
+ conn.isSecure());
+
+ // Get an instance of the selected cookie policy
+ CookieSpec cookieSpec = registry.getCookieSpec(policy, request.getParams());
+ // Get all cookies available in the HTTP state
+ List<Cookie> cookies = new ArrayList<Cookie>(cookieStore.getCookies());
+ // Find cookies matching the given origin
+ List<Cookie> matchedCookies = new ArrayList<Cookie>();
+ for (Cookie cookie : cookies) {
+ if (cookieSpec.match(cookie, cookieOrigin)) {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Cookie " + cookie + " match " + cookieOrigin);
+ }
+ matchedCookies.add(cookie);
+ }
+ }
+ // Generate Cookie request headers
+ if (!matchedCookies.isEmpty()) {
+ List<Header> headers = cookieSpec.formatCookies(matchedCookies);
+ for (Header header : headers) {
+ request.addHeader(header);
+ }
+ }
+
+ int ver = cookieSpec.getVersion();
+ if (ver > 0) {
+ boolean needVersionHeader = false;
+ for (Cookie cookie : matchedCookies) {
+ if (ver != cookie.getVersion()) {
+ needVersionHeader = true;
+ }
+ }
+
+ if (needVersionHeader) {
+ Header header = cookieSpec.getVersionHeader();
+ if (header != null) {
+ // Advertise cookie version support
+ request.addHeader(header);
+ }
+ }
+ }
+
+ // Stick the CookieSpec and CookieOrigin instances to the HTTP context
+ // so they could be obtained by the response interceptor
+ context.setAttribute(ClientContext.COOKIE_SPEC, cookieSpec);
+ context.setAttribute(ClientContext.COOKIE_ORIGIN, cookieOrigin);
+ }
+
+}
diff --git a/src/org/apache/http/client/protocol/RequestDefaultHeaders.java b/src/org/apache/http/client/protocol/RequestDefaultHeaders.java
new file mode 100644
index 0000000..27d5cc7
--- /dev/null
+++ b/src/org/apache/http/client/protocol/RequestDefaultHeaders.java
@@ -0,0 +1,74 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/RequestDefaultHeaders.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Request interceptor that adds default request headers.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 653041 $
+ *
+ * @since 4.0
+ */
+public class RequestDefaultHeaders implements HttpRequestInterceptor {
+
+ public RequestDefaultHeaders() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ // Add default headers
+ Collection<?> defHeaders = (Collection<?>) request.getParams().getParameter(
+ ClientPNames.DEFAULT_HEADERS);
+ if (defHeaders != null) {
+ for (Object defHeader : defHeaders) {
+ request.addHeader((Header) defHeader);
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/client/protocol/RequestProxyAuthentication.java b/src/org/apache/http/client/protocol/RequestProxyAuthentication.java
new file mode 100644
index 0000000..b4dfe76
--- /dev/null
+++ b/src/org/apache/http/client/protocol/RequestProxyAuthentication.java
@@ -0,0 +1,104 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/RequestProxyAuthentication.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 673450 $
+ *
+ * @since 4.0
+ */
+public class RequestProxyAuthentication implements HttpRequestInterceptor {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ public RequestProxyAuthentication() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ if (request.containsHeader(AUTH.PROXY_AUTH_RESP)) {
+ return;
+ }
+
+ // Obtain authentication state
+ AuthState authState = (AuthState) context.getAttribute(
+ ClientContext.PROXY_AUTH_STATE);
+ if (authState == null) {
+ return;
+ }
+
+ AuthScheme authScheme = authState.getAuthScheme();
+ if (authScheme == null) {
+ return;
+ }
+
+ Credentials creds = authState.getCredentials();
+ if (creds == null) {
+ this.log.debug("User credentials not available");
+ return;
+ }
+ if (authState.getAuthScope() != null || !authScheme.isConnectionBased()) {
+ try {
+ request.addHeader(authScheme.authenticate(creds, request));
+ } catch (AuthenticationException ex) {
+ if (this.log.isErrorEnabled()) {
+ this.log.error("Proxy authentication error: " + ex.getMessage());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/client/protocol/RequestTargetAuthentication.java b/src/org/apache/http/client/protocol/RequestTargetAuthentication.java
new file mode 100644
index 0000000..c140183
--- /dev/null
+++ b/src/org/apache/http/client/protocol/RequestTargetAuthentication.java
@@ -0,0 +1,105 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/RequestTargetAuthentication.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 673450 $
+ *
+ * @since 4.0
+ */
+public class RequestTargetAuthentication implements HttpRequestInterceptor {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ public RequestTargetAuthentication() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ if (request.containsHeader(AUTH.WWW_AUTH_RESP)) {
+ return;
+ }
+
+ // Obtain authentication state
+ AuthState authState = (AuthState) context.getAttribute(
+ ClientContext.TARGET_AUTH_STATE);
+ if (authState == null) {
+ return;
+ }
+
+ AuthScheme authScheme = authState.getAuthScheme();
+ if (authScheme == null) {
+ return;
+ }
+
+ Credentials creds = authState.getCredentials();
+ if (creds == null) {
+ this.log.debug("User credentials not available");
+ return;
+ }
+
+ if (authState.getAuthScope() != null || !authScheme.isConnectionBased()) {
+ try {
+ request.addHeader(authScheme.authenticate(creds, request));
+ } catch (AuthenticationException ex) {
+ if (this.log.isErrorEnabled()) {
+ this.log.error("Authentication error: " + ex.getMessage());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/client/protocol/ResponseProcessCookies.java b/src/org/apache/http/client/protocol/ResponseProcessCookies.java
new file mode 100644
index 0000000..0689e93
--- /dev/null
+++ b/src/org/apache/http/client/protocol/ResponseProcessCookies.java
@@ -0,0 +1,146 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ResponseProcessCookies.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.protocol;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.client.CookieStore;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Response interceptor that populates the current {@link CookieStore} with data
+ * contained in response cookies received in the given the HTTP response.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 673450 $
+ *
+ * @since 4.0
+ */
+public class ResponseProcessCookies implements HttpResponseInterceptor {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ public ResponseProcessCookies() {
+ super();
+ }
+
+ public void process(final HttpResponse response, final HttpContext context)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ // Obtain cookie store
+ CookieStore cookieStore = (CookieStore) context.getAttribute(
+ ClientContext.COOKIE_STORE);
+ if (cookieStore == null) {
+ this.log.info("Cookie store not available in HTTP context");
+ return;
+ }
+ // Obtain actual CookieSpec instance
+ CookieSpec cookieSpec = (CookieSpec) context.getAttribute(
+ ClientContext.COOKIE_SPEC);
+ if (cookieSpec == null) {
+ this.log.info("CookieSpec not available in HTTP context");
+ return;
+ }
+ // Obtain actual CookieOrigin instance
+ CookieOrigin cookieOrigin = (CookieOrigin) context.getAttribute(
+ ClientContext.COOKIE_ORIGIN);
+ if (cookieOrigin == null) {
+ this.log.info("CookieOrigin not available in HTTP context");
+ return;
+ }
+ HeaderIterator it = response.headerIterator(SM.SET_COOKIE);
+ processCookies(it, cookieSpec, cookieOrigin, cookieStore);
+
+ // see if the cookie spec supports cookie versioning.
+ if (cookieSpec.getVersion() > 0) {
+ // process set-cookie2 headers.
+ // Cookie2 will replace equivalent Cookie instances
+ it = response.headerIterator(SM.SET_COOKIE2);
+ processCookies(it, cookieSpec, cookieOrigin, cookieStore);
+ }
+ }
+
+ private void processCookies(
+ final HeaderIterator iterator,
+ final CookieSpec cookieSpec,
+ final CookieOrigin cookieOrigin,
+ final CookieStore cookieStore) {
+ while (iterator.hasNext()) {
+ Header header = iterator.nextHeader();
+ try {
+ List<Cookie> cookies = cookieSpec.parse(header, cookieOrigin);
+ for (Cookie cookie : cookies) {
+ try {
+ cookieSpec.validate(cookie, cookieOrigin);
+ cookieStore.addCookie(cookie);
+
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Cookie accepted: \""
+ + cookie + "\". ");
+ }
+ } catch (MalformedCookieException ex) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("Cookie rejected: \""
+ + cookie + "\". " + ex.getMessage());
+ }
+ }
+ }
+ } catch (MalformedCookieException ex) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("Invalid cookie header: \""
+ + header + "\". " + ex.getMessage());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/client/protocol/package.html b/src/org/apache/http/client/protocol/package.html
new file mode 100644
index 0000000..43dd0d6
--- /dev/null
+++ b/src/org/apache/http/client/protocol/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Additional request and response interceptors.
+
+</body>
+</html>
diff --git a/src/org/apache/http/client/utils/CloneUtils.java b/src/org/apache/http/client/utils/CloneUtils.java
new file mode 100644
index 0000000..fec534b
--- /dev/null
+++ b/src/org/apache/http/client/utils/CloneUtils.java
@@ -0,0 +1,75 @@
+/*
+ * $HeadURL:$
+ * $Revision:$
+ * $Date:$
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.client.utils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A collection of utilities to workaround limitations of Java clone framework.
+ */
+public class CloneUtils {
+
+ public static Object clone(final Object obj) throws CloneNotSupportedException {
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof Cloneable) {
+ Class<?> clazz = obj.getClass ();
+ Method m;
+ try {
+ m = clazz.getMethod("clone", (Class[]) null);
+ } catch (NoSuchMethodException ex) {
+ throw new NoSuchMethodError(ex.getMessage());
+ }
+ try {
+ return m.invoke(obj, (Object []) null);
+ } catch (InvocationTargetException ex) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof CloneNotSupportedException) {
+ throw ((CloneNotSupportedException) cause);
+ } else {
+ throw new Error("Unexpected exception", cause);
+ }
+ } catch (IllegalAccessException ex) {
+ throw new IllegalAccessError(ex.getMessage());
+ }
+ } else {
+ throw new CloneNotSupportedException();
+ }
+ }
+
+ /**
+ * This class should not be instantiated.
+ */
+ private CloneUtils() {
+ }
+
+}
diff --git a/src/org/apache/http/client/utils/URIUtils.java b/src/org/apache/http/client/utils/URIUtils.java
new file mode 100644
index 0000000..1cbb9af
--- /dev/null
+++ b/src/org/apache/http/client/utils/URIUtils.java
@@ -0,0 +1,209 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/utils/URIUtils.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.client.utils;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.http.HttpHost;
+
+/**
+ * A collection of utilities for {@link URI URIs}, to workaround
+ * bugs within the class or for ease-of-use features.
+ */
+public class URIUtils {
+
+ /**
+ * Constructs a {@link URI} using all the parameters. This should be
+ * used instead of
+ * {@link URI#URI(String, String, String, int, String, String, String)}
+ * or any of the other URI multi-argument URI constructors.
+ *
+ * See <a
+ * href="https://issues.apache.org/jira/browse/HTTPCLIENT-730">HTTPCLIENT-730</a>
+ * for more information.
+ *
+ * @param scheme
+ * Scheme name
+ * @param host
+ * Host name
+ * @param port
+ * Port number
+ * @param path
+ * Path
+ * @param query
+ * Query
+ * @param fragment
+ * Fragment
+ *
+ * @throws URISyntaxException
+ * If both a scheme and a path are given but the path is
+ * relative, if the URI string constructed from the given
+ * components violates RFC&nbsp;2396, or if the authority
+ * component of the string is present but cannot be parsed
+ * as a server-based authority
+ */
+ public static URI createURI(
+ final String scheme,
+ final String host,
+ int port,
+ final String path,
+ final String query,
+ final String fragment) throws URISyntaxException {
+
+ StringBuilder buffer = new StringBuilder();
+ if (host != null) {
+ if (scheme != null) {
+ buffer.append(scheme);
+ buffer.append("://");
+ }
+ buffer.append(host);
+ if (port > 0) {
+ buffer.append(':');
+ buffer.append(port);
+ }
+ }
+ if (path == null || !path.startsWith("/")) {
+ buffer.append('/');
+ }
+ if (path != null) {
+ buffer.append(path);
+ }
+ if (query != null) {
+ buffer.append('?');
+ buffer.append(query);
+ }
+ if (fragment != null) {
+ buffer.append('#');
+ buffer.append(fragment);
+ }
+ return new URI(buffer.toString());
+ }
+
+ /**
+ * A convenience method for creating a new {@link URI} whose scheme, host
+ * and port are taken from the target host, but whose path, query and
+ * fragment are taken from the existing URI. The fragment is only used if
+ * dropFragment is false.
+ *
+ * @param uri
+ * Contains the path, query and fragment to use.
+ * @param target
+ * Contains the scheme, host and port to use.
+ * @param dropFragment
+ * True if the fragment should not be copied.
+ *
+ * @throws URISyntaxException
+ * If the resulting URI is invalid.
+ */
+ public static URI rewriteURI(
+ final URI uri,
+ final HttpHost target,
+ boolean dropFragment) throws URISyntaxException {
+ if (uri == null) {
+ throw new IllegalArgumentException("URI may nor be null");
+ }
+ if (target != null) {
+ return URIUtils.createURI(
+ target.getSchemeName(),
+ target.getHostName(),
+ target.getPort(),
+ uri.getRawPath(),
+ uri.getRawQuery(),
+ dropFragment ? null : uri.getRawFragment());
+ } else {
+ return URIUtils.createURI(
+ null,
+ null,
+ -1,
+ uri.getRawPath(),
+ uri.getRawQuery(),
+ dropFragment ? null : uri.getRawFragment());
+ }
+ }
+
+ /**
+ * A convenience method for
+ * {@link URIUtils#rewriteURI(URI, HttpHost, boolean)} that always keeps the
+ * fragment.
+ */
+ public static URI rewriteURI(
+ final URI uri,
+ final HttpHost target) throws URISyntaxException {
+ return rewriteURI(uri, target, false);
+ }
+
+ /**
+ * Resolves a URI reference against a base URI. Work-around for bug in
+ * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+ *
+ * @param baseURI the base URI
+ * @param reference the URI reference
+ * @return the resulting URI
+ */
+ public static URI resolve(final URI baseURI, final String reference) {
+ return URIUtils.resolve(baseURI, URI.create(reference));
+ }
+
+ /**
+ * Resolves a URI reference against a base URI. Work-around for bug in
+ * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+ *
+ * @param baseURI the base URI
+ * @param reference the URI reference
+ * @return the resulting URI
+ */
+ public static URI resolve(final URI baseURI, URI reference){
+ if (baseURI == null) {
+ throw new IllegalArgumentException("Base URI may nor be null");
+ }
+ if (reference == null) {
+ throw new IllegalArgumentException("Reference URI may nor be null");
+ }
+ boolean emptyReference = reference.toString().length() == 0;
+ if (emptyReference) {
+ reference = URI.create("#");
+ }
+ URI resolved = baseURI.resolve(reference);
+ if (emptyReference) {
+ String resolvedString = resolved.toString();
+ resolved = URI.create(resolvedString.substring(0,
+ resolvedString.indexOf('#')));
+ }
+ return resolved;
+ }
+
+ /**
+ * This class should not be instantiated.
+ */
+ private URIUtils() {
+ }
+
+}
diff --git a/src/org/apache/http/client/utils/URLEncodedUtils.java b/src/org/apache/http/client/utils/URLEncodedUtils.java
new file mode 100644
index 0000000..8b08f90
--- /dev/null
+++ b/src/org/apache/http/client/utils/URLEncodedUtils.java
@@ -0,0 +1,191 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/utils/URLEncodedUtils.java $
+ * $Revision: 655107 $
+ * $Date: 2008-05-10 08:20:42 -0700 (Sat, 10 May 2008) $
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.utils;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Scanner;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * A collection of utilities for encoding URLs.
+ */
+public class URLEncodedUtils {
+
+ public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
+ private static final String PARAMETER_SEPARATOR = "&";
+ private static final String NAME_VALUE_SEPARATOR = "=";
+
+ /**
+ * Returns a list of {@link NameValuePair NameValuePairs} as built from the
+ * URI's query portion. For example, a URI of
+ * http://example.org/path/to/file?a=1&b=2&c=3 would return a list of three
+ * NameValuePairs, one for a=1, one for b=2, and one for c=3.
+ * <p>
+ * This is typically useful while parsing an HTTP PUT.
+ *
+ * @param uri
+ * uri to parse
+ * @param encoding
+ * encoding to use while parsing the query
+ */
+ public static List <NameValuePair> parse (final URI uri, final String encoding) {
+ List <NameValuePair> result = Collections.emptyList();
+ final String query = uri.getRawQuery();
+ if (query != null && query.length() > 0) {
+ result = new ArrayList <NameValuePair>();
+ parse(result, new Scanner(query), encoding);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a list of {@link NameValuePair NameValuePairs} as parsed from an
+ * {@link HttpEntity}. The encoding is taken from the entity's
+ * Content-Encoding header.
+ * <p>
+ * This is typically used while parsing an HTTP POST.
+ *
+ * @param entity
+ * The entity to parse
+ * @throws IOException
+ * If there was an exception getting the entity's data.
+ */
+ public static List <NameValuePair> parse (
+ final HttpEntity entity) throws IOException {
+ List <NameValuePair> result = Collections.emptyList();
+ if (isEncoded(entity)) {
+ final String content = EntityUtils.toString(entity);
+ final Header encoding = entity.getContentEncoding();
+ if (content != null && content.length() > 0) {
+ result = new ArrayList <NameValuePair>();
+ parse(result, new Scanner(content),
+ encoding != null ? encoding.getValue() : null);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns true if the entity's Content-Type header is
+ * <code>application/x-www-form-urlencoded</code>.
+ */
+ public static boolean isEncoded (final HttpEntity entity) {
+ final Header contentType = entity.getContentType();
+ return (contentType != null && contentType.getValue().equalsIgnoreCase(CONTENT_TYPE));
+ }
+
+ /**
+ * Adds all parameters within the Scanner to the list of
+ * <code>parameters</code>, as encoded by <code>encoding</code>. For
+ * example, a scanner containing the string <code>a=1&b=2&c=3</code> would
+ * add the {@link NameValuePair NameValuePairs} a=1, b=2, and c=3 to the
+ * list of parameters.
+ *
+ * @param parameters
+ * List to add parameters to.
+ * @param scanner
+ * Input that contains the parameters to parse.
+ * @param encoding
+ * Encoding to use when decoding the parameters.
+ */
+ public static void parse (
+ final List <NameValuePair> parameters,
+ final Scanner scanner,
+ final String encoding) {
+ scanner.useDelimiter(PARAMETER_SEPARATOR);
+ while (scanner.hasNext()) {
+ final String[] nameValue = scanner.next().split(NAME_VALUE_SEPARATOR);
+ if (nameValue.length == 0 || nameValue.length > 2)
+ throw new IllegalArgumentException("bad parameter");
+
+ final String name = decode(nameValue[0], encoding);
+ String value = null;
+ if (nameValue.length == 2)
+ value = decode(nameValue[1], encoding);
+ parameters.add(new BasicNameValuePair(name, value));
+ }
+ }
+
+ /**
+ * Returns a String that is suitable for use as an <code>application/x-www-form-urlencoded</code>
+ * list of parameters in an HTTP PUT or HTTP POST.
+ *
+ * @param parameters The parameters to include.
+ * @param encoding The encoding to use.
+ */
+ public static String format (
+ final List <? extends NameValuePair> parameters,
+ final String encoding) {
+ final StringBuilder result = new StringBuilder();
+ for (final NameValuePair parameter : parameters) {
+ final String encodedName = encode(parameter.getName(), encoding);
+ final String value = parameter.getValue();
+ final String encodedValue = value != null ? encode(value, encoding) : "";
+ if (result.length() > 0)
+ result.append(PARAMETER_SEPARATOR);
+ result.append(encodedName);
+ result.append(NAME_VALUE_SEPARATOR);
+ result.append(encodedValue);
+ }
+ return result.toString();
+ }
+
+ private static String decode (final String content, final String encoding) {
+ try {
+ return URLDecoder.decode(content,
+ encoding != null ? encoding : HTTP.DEFAULT_CONTENT_CHARSET);
+ } catch (UnsupportedEncodingException problem) {
+ throw new IllegalArgumentException(problem);
+ }
+ }
+
+ private static String encode (final String content, final String encoding) {
+ try {
+ return URLEncoder.encode(content,
+ encoding != null ? encoding : HTTP.DEFAULT_CONTENT_CHARSET);
+ } catch (UnsupportedEncodingException problem) {
+ throw new IllegalArgumentException(problem);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/client/utils/package.html b/src/org/apache/http/client/utils/package.html
new file mode 100644
index 0000000..7abeb93
--- /dev/null
+++ b/src/org/apache/http/client/utils/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/utils/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Helpers and utility classes for <i>HttpClient</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/conn/BasicEofSensorWatcher.java b/src/org/apache/http/conn/BasicEofSensorWatcher.java
new file mode 100644
index 0000000..9a9f3c5
--- /dev/null
+++ b/src/org/apache/http/conn/BasicEofSensorWatcher.java
@@ -0,0 +1,121 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/BasicEofSensorWatcher.java $
+ * $Revision $
+ * $Date: 2008-06-27 12:49:20 -0700 (Fri, 27 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * Basic implementation of {@link EofSensorWatcher EofSensorWatcher}.
+ * The underlying connection is released on close or EOF.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 672367 $
+ *
+ * @since 4.0
+ */
+public class BasicEofSensorWatcher implements EofSensorWatcher {
+
+
+ /** The connection to auto-release. */
+ protected ManagedClientConnection managedConn;
+
+ /** Whether to keep the connection alive. */
+ protected boolean attemptReuse;
+
+
+
+ /**
+ * Creates a new watcher for auto-releasing a connection.
+ *
+ * @param conn the connection to auto-release
+ * @param reuse whether the connection should be re-used
+ */
+ public BasicEofSensorWatcher(ManagedClientConnection conn,
+ boolean reuse) {
+ if (conn == null)
+ throw new IllegalArgumentException
+ ("Connection may not be null.");
+
+ managedConn = conn;
+ attemptReuse = reuse;
+ }
+
+
+ // non-javadoc, see interface EofSensorWatcher
+ public boolean eofDetected(InputStream wrapped)
+ throws IOException {
+
+ try {
+ if (attemptReuse) {
+ // there may be some cleanup required, such as
+ // reading trailers after the response body:
+ wrapped.close();
+ managedConn.markReusable();
+ }
+ } finally {
+ managedConn.releaseConnection();
+ }
+ return false;
+ }
+
+
+ // non-javadoc, see interface EofSensorWatcher
+ public boolean streamClosed(InputStream wrapped)
+ throws IOException {
+
+ try {
+ if (attemptReuse) {
+ // this assumes that closing the stream will
+ // consume the remainder of the response body:
+ wrapped.close();
+ managedConn.markReusable();
+ }
+ } finally {
+ managedConn.releaseConnection();
+ }
+ return false;
+ }
+
+
+ // non-javadoc, see interface EofSensorWatcher
+ public boolean streamAbort(InputStream wrapped)
+ throws IOException {
+
+ managedConn.abortConnection();
+ return false;
+ }
+
+} // class BasicEofSensorWatcher
diff --git a/src/org/apache/http/conn/BasicManagedEntity.java b/src/org/apache/http/conn/BasicManagedEntity.java
new file mode 100644
index 0000000..9719e1a
--- /dev/null
+++ b/src/org/apache/http/conn/BasicManagedEntity.java
@@ -0,0 +1,220 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/BasicManagedEntity.java $
+ * $Revision $
+ * $Date: 2008-06-27 12:49:20 -0700 (Fri, 27 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.HttpEntityWrapper;
+
+
+/**
+ * An entity that releases a {@link ManagedClientConnection connection}.
+ * A {@link ManagedClientConnection} will
+ * typically <i>not</i> return a managed entity, but you can replace
+ * the unmanaged entity in the response with a managed one.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 672367 $
+ *
+ * @since 4.0
+ */
+public class BasicManagedEntity extends HttpEntityWrapper
+ implements ConnectionReleaseTrigger, EofSensorWatcher {
+
+ /** The connection to release. */
+ protected ManagedClientConnection managedConn;
+
+ /** Whether to keep the connection alive. */
+ protected final boolean attemptReuse;
+
+
+ /**
+ * Creates a new managed entity that can release a connection.
+ *
+ * @param entity the entity of which to wrap the content.
+ * Note that the argument entity can no longer be used
+ * afterwards, since the content will be taken by this
+ * managed entity.
+ * @param conn the connection to release
+ * @param reuse whether the connection should be re-used
+ */
+ public BasicManagedEntity(HttpEntity entity,
+ ManagedClientConnection conn,
+ boolean reuse) {
+ super(entity);
+
+ if (conn == null)
+ throw new IllegalArgumentException
+ ("Connection may not be null.");
+
+ this.managedConn = conn;
+ this.attemptReuse = reuse;
+ }
+
+
+ // non-javadoc, see interface HttpEntity
+ @Override
+ public boolean isRepeatable() {
+ return false;
+ }
+
+
+ // non-javadoc, see interface HttpEntity
+ @Override
+ public InputStream getContent() throws IOException {
+
+ return new EofSensorInputStream(wrappedEntity.getContent(), this);
+ }
+
+
+ // non-javadoc, see interface HttpEntity
+ @Override
+ public void consumeContent() throws IOException {
+
+ if (managedConn == null)
+ return;
+
+ try {
+ if (attemptReuse) {
+ // this will not trigger a callback from EofSensorInputStream
+ wrappedEntity.consumeContent();
+ managedConn.markReusable();
+ }
+ } finally {
+ releaseManagedConnection();
+ }
+ }
+
+
+ // non-javadoc, see interface HttpEntity
+ @Override
+ public void writeTo(final OutputStream outstream) throws IOException {
+ super.writeTo(outstream);
+ consumeContent();
+ }
+
+
+ // non-javadoc, see interface ConnectionReleaseTrigger
+ public void releaseConnection()
+ throws IOException {
+
+ this.consumeContent();
+ }
+
+
+ // non-javadoc, see interface ConnectionReleaseTrigger
+ public void abortConnection()
+ throws IOException {
+
+ if (managedConn != null) {
+ try {
+ managedConn.abortConnection();
+ } finally {
+ managedConn = null;
+ }
+ }
+ }
+
+
+ // non-javadoc, see interface EofSensorWatcher
+ public boolean eofDetected(InputStream wrapped)
+ throws IOException {
+
+ try {
+ if (attemptReuse && (managedConn != null)) {
+ // there may be some cleanup required, such as
+ // reading trailers after the response body:
+ wrapped.close();
+ managedConn.markReusable();
+ }
+ } finally {
+ releaseManagedConnection();
+ }
+ return false;
+ }
+
+
+ // non-javadoc, see interface EofSensorWatcher
+ public boolean streamClosed(InputStream wrapped)
+ throws IOException {
+
+ try {
+ if (attemptReuse && (managedConn != null)) {
+ // this assumes that closing the stream will
+ // consume the remainder of the response body:
+ wrapped.close();
+ managedConn.markReusable();
+ }
+ } finally {
+ releaseManagedConnection();
+ }
+ return false;
+ }
+
+
+ // non-javadoc, see interface EofSensorWatcher
+ public boolean streamAbort(InputStream wrapped)
+ throws IOException {
+
+ if (managedConn != null) {
+ managedConn.abortConnection();
+ }
+ return false;
+ }
+
+
+ /**
+ * Releases the connection gracefully.
+ * The connection attribute will be nullified.
+ * Subsequent invocations are no-ops.
+ *
+ * @throws IOException in case of an IO problem.
+ * The connection attribute will be nullified anyway.
+ */
+ protected void releaseManagedConnection()
+ throws IOException {
+
+ if (managedConn != null) {
+ try {
+ managedConn.releaseConnection();
+ } finally {
+ managedConn = null;
+ }
+ }
+ }
+
+} // class BasicManagedEntity
diff --git a/src/org/apache/http/conn/ClientConnectionManager.java b/src/org/apache/http/conn/ClientConnectionManager.java
new file mode 100644
index 0000000..e3375e1
--- /dev/null
+++ b/src/org/apache/http/conn/ClientConnectionManager.java
@@ -0,0 +1,129 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ClientConnectionManager.java $
+ * $Revision: 671717 $
+ * $Date: 2008-06-25 21:03:24 -0700 (Wed, 25 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.scheme.SchemeRegistry;
+
+/**
+ * Management interface for {@link ManagedClientConnection client connections}.
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 671717 $
+ *
+ * @since 4.0
+ */
+public interface ClientConnectionManager {
+
+ /**
+ * Obtains the scheme registry used by this manager.
+ *
+ * @return the scheme registry, never <code>null</code>
+ */
+ SchemeRegistry getSchemeRegistry()
+ ;
+
+
+ /**
+ * Returns a new {@link ClientConnectionRequest}, from which a
+ * {@link ManagedClientConnection} can be obtained or the request can be
+ * aborted.
+ */
+ ClientConnectionRequest requestConnection(HttpRoute route, Object state)
+ ;
+
+
+ /**
+ * Releases a connection for use by others.
+ * You may optionally specify how long the connection is valid
+ * to be reused. Values <= 0 are considered to be valid forever.
+ * If the connection is not marked as reusable, the connection will
+ * not be reused regardless of the valid duration.
+ *
+ * If the connection has been released before,
+ * the call will be ignored.
+ *
+ * @param conn the connection to release
+ * @param validDuration the duration of time this connection is valid for reuse
+ * @param timeUnit the unit of time validDuration is measured in
+ *
+ * @see #closeExpiredConnections()
+ */
+ void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit)
+ ;
+
+
+ /**
+ * Closes idle connections in the pool.
+ * Open connections in the pool that have not been used for the
+ * timespan given by the argument will be closed.
+ * Currently allocated connections are not subject to this method.
+ * Times will be checked with milliseconds precision
+ *
+ * All expired connections will also be closed.
+ *
+ * @param idletime the idle time of connections to be closed
+ * @param tunit the unit for the <code>idletime</code>
+ *
+ * @see #closeExpiredConnections()
+ */
+ void closeIdleConnections(long idletime, TimeUnit tunit)
+ ;
+
+ /**
+ * Closes all expired connections in the pool.
+ * Open connections in the pool that have not been used for
+ * the timespan defined when the connection was released will be closed.
+ * Currently allocated connections are not subject to this method.
+ * Times will be checked with milliseconds precision.
+ */
+ void closeExpiredConnections();
+
+ /**
+ * Shuts down this connection manager and releases allocated resources.
+ * This includes closing all connections, whether they are currently
+ * used or not.
+ */
+ void shutdown()
+ ;
+
+
+} // interface ClientConnectionManager
diff --git a/src/org/apache/http/conn/ClientConnectionManagerFactory.java b/src/org/apache/http/conn/ClientConnectionManagerFactory.java
new file mode 100644
index 0000000..4bedc4e
--- /dev/null
+++ b/src/org/apache/http/conn/ClientConnectionManagerFactory.java
@@ -0,0 +1,50 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ClientConnectionManagerFactory.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.params.HttpParams;
+
+/**
+ * A factory for creating new {@link ClientConnectionManager} instances.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface ClientConnectionManagerFactory {
+
+ ClientConnectionManager newInstance(
+ HttpParams params,
+ SchemeRegistry schemeRegistry);
+
+}
diff --git a/src/org/apache/http/conn/ClientConnectionOperator.java b/src/org/apache/http/conn/ClientConnectionOperator.java
new file mode 100644
index 0000000..980b867
--- /dev/null
+++ b/src/org/apache/http/conn/ClientConnectionOperator.java
@@ -0,0 +1,120 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ClientConnectionOperator.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+import org.apache.http.conn.scheme.SocketFactory;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+
+
+
+/**
+ * Interface for opening {@link OperatedClientConnection connections}.
+ * This interface encapsulates the logic to create sockets and to
+ * open or update the connection with the new socket.
+ * Implementations will most likely make use of
+ * {@link SocketFactory socket factories}.
+ * <br/>
+ * The methods in this interface allow the creation of plain and layered
+ * sockets. Creating a tunnelled connection through a proxy, however,
+ * is not within the scope of the operator.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 645850 $ $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * @since 4.0
+ */
+public interface ClientConnectionOperator {
+
+
+ /**
+ * Creates a new connection that can be operated.
+ *
+ * @return a new, unopened connection for use with this operator
+ */
+ OperatedClientConnection createConnection()
+ ;
+
+
+ /**
+ * Opens a connection to the given target host.
+ *
+ * @param conn the connection to open
+ * @param target the target host to connect to
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ * @param context the context for the connection
+ * @param params the parameters for the connection
+ *
+ * @throws IOException in case of a problem
+ */
+ void openConnection(OperatedClientConnection conn,
+ HttpHost target,
+ InetAddress local,
+ HttpContext context,
+ HttpParams params)
+ throws IOException
+ ;
+
+
+ /**
+ * Updates a connection with a layered secure connection.
+ * The typical use of this method is to update a tunnelled plain
+ * connection (HTTP) to a secure TLS/SSL connection (HTTPS).
+ *
+ * @param conn the open connection to update
+ * @param target the target host for the updated connection.
+ * The connection must already be open or tunnelled
+ * to the host and port, but the scheme of the target
+ * will be used to create a layered connection.
+ * @param context the context for the connection
+ * @param params the parameters for the updated connection
+ *
+ * @throws IOException in case of a problem
+ */
+ void updateSecureConnection(OperatedClientConnection conn,
+ HttpHost target,
+ HttpContext context,
+ HttpParams params)
+ throws IOException
+ ;
+
+
+} // interface ClientConnectionOperator
+
diff --git a/src/org/apache/http/conn/ClientConnectionRequest.java b/src/org/apache/http/conn/ClientConnectionRequest.java
new file mode 100644
index 0000000..6ba02d0
--- /dev/null
+++ b/src/org/apache/http/conn/ClientConnectionRequest.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ClientConnectionRequest.java $
+ * $Revision: 651815 $
+ * $Date: 2008-04-26 04:14:43 -0700 (Sat, 26 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Encapsulates a request for a {@link ManagedClientConnection}.
+ */
+public interface ClientConnectionRequest {
+
+ /**
+ * Obtains a connection within a given time.
+ * This method will block until a connection becomes available,
+ * the timeout expires, or the connection manager is
+ * {@link ClientConnectionManager#shutdown() shut down}.
+ * Timeouts are handled with millisecond precision.
+ *
+ * If {@link #abortRequest()} is called while this is blocking or
+ * before this began, an {@link InterruptedException} will
+ * be thrown.
+ *
+ * @param timeout the timeout, 0 or negative for no timeout
+ * @param tunit the unit for the <code>timeout</code>,
+ * may be <code>null</code> only if there is no timeout
+ *
+ * @return a connection that can be used to communicate
+ * along the given route
+ *
+ * @throws ConnectionPoolTimeoutException
+ * in case of a timeout
+ * @throws InterruptedException
+ * if the calling thread is interrupted while waiting
+ */
+ ManagedClientConnection getConnection(long timeout, TimeUnit tunit)
+ throws InterruptedException, ConnectionPoolTimeoutException;
+
+ /**
+ * Aborts the call to {@link #getConnection(long, TimeUnit)},
+ * causing it to throw an {@link InterruptedException}.
+ */
+ void abortRequest();
+
+}
diff --git a/src/org/apache/http/conn/ConnectTimeoutException.java b/src/org/apache/http/conn/ConnectTimeoutException.java
new file mode 100644
index 0000000..83a731a
--- /dev/null
+++ b/src/org/apache/http/conn/ConnectTimeoutException.java
@@ -0,0 +1,64 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ConnectTimeoutException.java $
+ * $Revision: 617645 $
+ * $Date: 2008-02-01 13:05:31 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.InterruptedIOException;
+
+/**
+ * A timeout while connecting to an HTTP server or waiting for an
+ * available connection from an HttpConnectionManager.
+ *
+ * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
+ *
+ * @since 4.0
+ */
+public class ConnectTimeoutException extends InterruptedIOException {
+
+ private static final long serialVersionUID = -4816682903149535989L;
+
+ /**
+ * Creates a ConnectTimeoutException with a <tt>null</tt> detail message.
+ */
+ public ConnectTimeoutException() {
+ super();
+ }
+
+ /**
+ * Creates a ConnectTimeoutException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public ConnectTimeoutException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/conn/ConnectionKeepAliveStrategy.java b/src/org/apache/http/conn/ConnectionKeepAliveStrategy.java
new file mode 100644
index 0000000..27d56cb
--- /dev/null
+++ b/src/org/apache/http/conn/ConnectionKeepAliveStrategy.java
@@ -0,0 +1,71 @@
+/*
+ * $HeadURL: $
+ * $Revision: $
+ * $Date: $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.conn;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpResponse;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Interface for deciding how long a connection can remain
+ * idle before being reused.
+ *
+ * @author <a href="mailto:sberlin at gmail.com">Sam Berlin</a>
+ *
+ *
+ * @version $Revision: $
+ *
+ * @since 4.0
+ */
+public interface ConnectionKeepAliveStrategy {
+
+ /**
+ * Returns the duration of time which this connection can be safely kept
+ * idle. If the connection is left idle for longer than this period of time,
+ * it MUST not reused. A value of 0 or less may be returned to indicate that
+ * there is no suitable suggestion.
+ *
+ * When coupled with a {@link ConnectionReuseStrategy}, if
+ * {@link ConnectionReuseStrategy#keepAlive(HttpResponse, HttpContext)
+ * returns true, this allows you to control how long the reuse will last. If
+ * keepAlive returns false, this should have no meaningful impact
+ *
+ * @param response
+ * The last response received over the connection.
+ * @param context
+ * the context in which the connection is being used.
+ *
+ * @return the duration in ms for which it is safe to keep the connection
+ * idle, or <=0 if no suggested duration.
+ */
+ long getKeepAliveDuration(HttpResponse response, HttpContext context);
+
+}
diff --git a/src/org/apache/http/conn/ConnectionPoolTimeoutException.java b/src/org/apache/http/conn/ConnectionPoolTimeoutException.java
new file mode 100644
index 0000000..7d4985e
--- /dev/null
+++ b/src/org/apache/http/conn/ConnectionPoolTimeoutException.java
@@ -0,0 +1,62 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ConnectionPoolTimeoutException.java $
+ * $Revision: 505684 $
+ * $Date: 2007-02-10 04:40:02 -0800 (Sat, 10 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+/**
+ * A timeout while waiting for an available connection
+ * from a connection manager.
+ *
+ * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
+ *
+ * @since 4.0
+ */
+public class ConnectionPoolTimeoutException extends ConnectTimeoutException {
+
+ private static final long serialVersionUID = -7898874842020245128L;
+
+ /**
+ * Creates a ConnectTimeoutException with a <tt>null</tt> detail message.
+ */
+ public ConnectionPoolTimeoutException() {
+ super();
+ }
+
+ /**
+ * Creates a ConnectTimeoutException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public ConnectionPoolTimeoutException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/conn/ConnectionReleaseTrigger.java b/src/org/apache/http/conn/ConnectionReleaseTrigger.java
new file mode 100644
index 0000000..a9ac12e
--- /dev/null
+++ b/src/org/apache/http/conn/ConnectionReleaseTrigger.java
@@ -0,0 +1,86 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ConnectionReleaseTrigger.java $
+ * $Revision: 672367 $
+ * $Date: 2008-06-27 12:49:20 -0700 (Fri, 27 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.IOException;
+
+
+/**
+ * Interface for releasing a connection.
+ * This can be implemented by various "trigger" objects which are
+ * associated with a connection, for example
+ * a {@link EofSensorInputStream stream}
+ * or an {@link BasicManagedEntity entity}
+ * or the {@link ManagedClientConnection connection} itself.
+ * <br/>
+ * The methods in this interface can safely be called multiple times.
+ * The first invocation releases the connection, subsequent calls
+ * are ignored.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 672367 $
+ *
+ * @since 4.0
+ */
+public interface ConnectionReleaseTrigger {
+
+ /**
+ * Releases the connection with the option of keep-alive. This is a
+ * "graceful" release and may cause IO operations for consuming the
+ * remainder of a response entity. Use
+ * {@link #abortConnection abortConnection} for a hard release. The
+ * connection may be reused as specified by the duration.
+ *
+ * @throws IOException
+ * in case of an IO problem. The connection will be released
+ * anyway.
+ */
+ void releaseConnection()
+ throws IOException
+ ;
+
+ /**
+ * Releases the connection without the option of keep-alive.
+ * This is a "hard" release that implies a shutdown of the connection.
+ * Use {@link #releaseConnection releaseConnection} for a graceful release.
+ *
+ * @throws IOException in case of an IO problem.
+ * The connection will be released anyway.
+ */
+ void abortConnection()
+ throws IOException
+ ;
+
+
+} // interface ConnectionReleaseTrigger
diff --git a/src/org/apache/http/conn/EofSensorInputStream.java b/src/org/apache/http/conn/EofSensorInputStream.java
new file mode 100644
index 0000000..0e1b90e
--- /dev/null
+++ b/src/org/apache/http/conn/EofSensorInputStream.java
@@ -0,0 +1,326 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/EofSensorInputStream.java $
+ * $Revision: 672367 $
+ * $Date: 2008-06-27 12:49:20 -0700 (Fri, 27 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * A stream wrapper that triggers actions on {@link #close close()} and EOF.
+ * Primarily used to auto-release an underlying
+ * {@link ManagedClientConnection connection}
+ * when the response body is consumed or no longer needed.
+ *
+ * <p>
+ * This class is based on <code>AutoCloseInputStream</code> in HttpClient 3.1,
+ * but has notable differences. It does not allow mark/reset, distinguishes
+ * different kinds of event, and does not always close the underlying stream
+ * on EOF. That decision is left to the {@link EofSensorWatcher watcher}.
+ * </p>
+ *
+ * @see EofSensorWatcher EofSensorWatcher
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author Ortwin Glueck
+ * @author Eric Johnson
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 672367 $
+ *
+ * @since 4.0
+ */
+// don't use FilterInputStream as the base class, we'd have to
+// override markSupported(), mark(), and reset() to disable them
+public class EofSensorInputStream extends InputStream
+ implements ConnectionReleaseTrigger {
+
+ /**
+ * The wrapped input stream, while accessible.
+ * The value changes to <code>null</code> when the wrapped stream
+ * becomes inaccessible.
+ */
+ protected InputStream wrappedStream;
+
+
+ /**
+ * Indicates whether this stream itself is closed.
+ * If it isn't, but {@link #wrappedStream wrappedStream}
+ * is <code>null</code>, we're running in EOF mode.
+ * All read operations will indicate EOF without accessing
+ * the underlying stream. After closing this stream, read
+ * operations will trigger an {@link IOException IOException}.
+ *
+ * @see #isReadAllowed isReadAllowed
+ */
+ private boolean selfClosed;
+
+ /** The watcher to be notified, if any. */
+ private EofSensorWatcher eofWatcher;
+
+
+ /**
+ * Creates a new EOF sensor.
+ * If no watcher is passed, the underlying stream will simply be
+ * closed when EOF is detected or {@link #close close} is called.
+ * Otherwise, the watcher decides whether the underlying stream
+ * should be closed before detaching from it.
+ *
+ * @param in the wrapped stream
+ * @param watcher the watcher for events, or <code>null</code> for
+ * auto-close behavior without notification
+ */
+ public EofSensorInputStream(final InputStream in,
+ final EofSensorWatcher watcher) {
+ if (in == null) {
+ throw new IllegalArgumentException
+ ("Wrapped stream may not be null.");
+ }
+
+ wrappedStream = in;
+ selfClosed = false;
+ eofWatcher = watcher;
+ }
+
+
+ /**
+ * Checks whether the underlying stream can be read from.
+ *
+ * @return <code>true</code> if the underlying stream is accessible,
+ * <code>false</code> if this stream is in EOF mode and
+ * detached from the underlying stream
+ *
+ * @throws IOException if this stream is already closed
+ */
+ protected boolean isReadAllowed() throws IOException {
+ if (selfClosed) {
+ throw new IOException("Attempted read on closed stream.");
+ }
+ return (wrappedStream != null);
+ }
+
+
+ // non-javadoc, see base class InputStream
+ @Override
+ public int read() throws IOException {
+ int l = -1;
+
+ if (isReadAllowed()) {
+ try {
+ l = wrappedStream.read();
+ checkEOF(l);
+ } catch (IOException ex) {
+ checkAbort();
+ throw ex;
+ }
+ }
+
+ return l;
+ }
+
+
+ // non-javadoc, see base class InputStream
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int l = -1;
+
+ if (isReadAllowed()) {
+ try {
+ l = wrappedStream.read(b, off, len);
+ checkEOF(l);
+ } catch (IOException ex) {
+ checkAbort();
+ throw ex;
+ }
+ }
+
+ return l;
+ }
+
+
+ // non-javadoc, see base class InputStream
+ @Override
+ public int read(byte[] b) throws IOException {
+ int l = -1;
+
+ if (isReadAllowed()) {
+ try {
+ l = wrappedStream.read(b);
+ checkEOF(l);
+ } catch (IOException ex) {
+ checkAbort();
+ throw ex;
+ }
+ }
+ return l;
+ }
+
+
+ // non-javadoc, see base class InputStream
+ @Override
+ public int available() throws IOException {
+ int a = 0; // not -1
+
+ if (isReadAllowed()) {
+ try {
+ a = wrappedStream.available();
+ // no checkEOF() here, available() can't trigger EOF
+ } catch (IOException ex) {
+ checkAbort();
+ throw ex;
+ }
+ }
+
+ return a;
+ }
+
+
+ // non-javadoc, see base class InputStream
+ @Override
+ public void close() throws IOException {
+ // tolerate multiple calls to close()
+ selfClosed = true;
+ checkClose();
+ }
+
+
+ /**
+ * Detects EOF and notifies the watcher.
+ * This method should only be called while the underlying stream is
+ * still accessible. Use {@link #isReadAllowed isReadAllowed} to
+ * check that condition.
+ * <br/>
+ * If EOF is detected, the watcher will be notified and this stream
+ * is detached from the underlying stream. This prevents multiple
+ * notifications from this stream.
+ *
+ * @param eof the result of the calling read operation.
+ * A negative value indicates that EOF is reached.
+ *
+ * @throws IOException
+ * in case of an IO problem on closing the underlying stream
+ */
+ protected void checkEOF(int eof) throws IOException {
+
+ if ((wrappedStream != null) && (eof < 0)) {
+ try {
+ boolean scws = true; // should close wrapped stream?
+ if (eofWatcher != null)
+ scws = eofWatcher.eofDetected(wrappedStream);
+ if (scws)
+ wrappedStream.close();
+ } finally {
+ wrappedStream = null;
+ }
+ }
+ }
+
+
+ /**
+ * Detects stream close and notifies the watcher.
+ * There's not much to detect since this is called by {@link #close close}.
+ * The watcher will only be notified if this stream is closed
+ * for the first time and before EOF has been detected.
+ * This stream will be detached from the underlying stream to prevent
+ * multiple notifications to the watcher.
+ *
+ * @throws IOException
+ * in case of an IO problem on closing the underlying stream
+ */
+ protected void checkClose() throws IOException {
+
+ if (wrappedStream != null) {
+ try {
+ boolean scws = true; // should close wrapped stream?
+ if (eofWatcher != null)
+ scws = eofWatcher.streamClosed(wrappedStream);
+ if (scws)
+ wrappedStream.close();
+ } finally {
+ wrappedStream = null;
+ }
+ }
+ }
+
+
+ /**
+ * Detects stream abort and notifies the watcher.
+ * There's not much to detect since this is called by
+ * {@link #abortConnection abortConnection}.
+ * The watcher will only be notified if this stream is aborted
+ * for the first time and before EOF has been detected or the
+ * stream has been {@link #close closed} gracefully.
+ * This stream will be detached from the underlying stream to prevent
+ * multiple notifications to the watcher.
+ *
+ * @throws IOException
+ * in case of an IO problem on closing the underlying stream
+ */
+ protected void checkAbort() throws IOException {
+
+ if (wrappedStream != null) {
+ try {
+ boolean scws = true; // should close wrapped stream?
+ if (eofWatcher != null)
+ scws = eofWatcher.streamAbort(wrappedStream);
+ if (scws)
+ wrappedStream.close();
+ } finally {
+ wrappedStream = null;
+ }
+ }
+ }
+
+
+ /**
+ * Same as {@link #close close()}.
+ */
+ public void releaseConnection() throws IOException {
+ this.close();
+ }
+
+ /**
+ * Aborts this stream.
+ * This is a special version of {@link #close close()} which prevents
+ * re-use of the underlying connection, if any. Calling this method
+ * indicates that there should be no attempt to read until the end of
+ * the stream.
+ */
+ public void abortConnection() throws IOException {
+ // tolerate multiple calls
+ selfClosed = true;
+ checkAbort();
+ }
+
+} // class EOFSensorInputStream
+
diff --git a/src/org/apache/http/conn/EofSensorWatcher.java b/src/org/apache/http/conn/EofSensorWatcher.java
new file mode 100644
index 0000000..837f8d9
--- /dev/null
+++ b/src/org/apache/http/conn/EofSensorWatcher.java
@@ -0,0 +1,112 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/EofSensorWatcher.java $
+ * $Revision: 552264 $
+ * $Date: 2007-07-01 02:37:47 -0700 (Sun, 01 Jul 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * A watcher for {@link EofSensorInputStream EofSensorInputStream}.
+ * Each stream will notify it's watcher at most once.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 552264 $
+ *
+ * @since 4.0
+ */
+public interface EofSensorWatcher {
+
+ /**
+ * Indicates that EOF is detected.
+ *
+ * @param wrapped the underlying stream which has reached EOF
+ *
+ * @return <code>true</code> if <code>wrapped</code> should be closed,
+ * <code>false</code> if it should be left alone
+ *
+ * @throws IOException
+ * in case of an IO problem, for example if the watcher itself
+ * closes the underlying stream. The caller will leave the
+ * wrapped stream alone, as if <code>false</code> was returned.
+ */
+ boolean eofDetected(InputStream wrapped)
+ throws IOException
+ ;
+
+
+ /**
+ * Indicates that the {@link EofSensorInputStream stream} is closed.
+ * This method will be called only if EOF was <i>not</i> detected
+ * before closing. Otherwise, {@link #eofDetected eofDetected} is called.
+ *
+ * @param wrapped the underlying stream which has not reached EOF
+ *
+ * @return <code>true</code> if <code>wrapped</code> should be closed,
+ * <code>false</code> if it should be left alone
+ *
+ * @throws IOException
+ * in case of an IO problem, for example if the watcher itself
+ * closes the underlying stream. The caller will leave the
+ * wrapped stream alone, as if <code>false</code> was returned.
+ */
+ boolean streamClosed(InputStream wrapped)
+ throws IOException
+ ;
+
+
+ /**
+ * Indicates that the {@link EofSensorInputStream stream} is aborted.
+ * This method will be called only if EOF was <i>not</i> detected
+ * before aborting. Otherwise, {@link #eofDetected eofDetected} is called.
+ * <p/>
+ * This method will also be invoked when an input operation causes an
+ * IOException to be thrown to make sure the input stream gets shut down.
+ *
+ * @param wrapped the underlying stream which has not reached EOF
+ *
+ * @return <code>true</code> if <code>wrapped</code> should be closed,
+ * <code>false</code> if it should be left alone
+ *
+ * @throws IOException
+ * in case of an IO problem, for example if the watcher itself
+ * closes the underlying stream. The caller will leave the
+ * wrapped stream alone, as if <code>false</code> was returned.
+ */
+ boolean streamAbort(InputStream wrapped)
+ throws IOException
+ ;
+
+
+} // interface EofSensorWatcher
diff --git a/src/org/apache/http/conn/HttpHostConnectException.java b/src/org/apache/http/conn/HttpHostConnectException.java
new file mode 100644
index 0000000..743ca77
--- /dev/null
+++ b/src/org/apache/http/conn/HttpHostConnectException.java
@@ -0,0 +1,57 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/HttpHostConnectException.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.net.ConnectException;
+
+import org.apache.http.HttpHost;
+
+/**
+ * A {@link ConnectException} that specifies the {@link HttpHost} that was
+ * being connected to.
+ */
+public class HttpHostConnectException extends ConnectException {
+
+ private static final long serialVersionUID = -3194482710275220224L;
+
+ private final HttpHost host;
+
+ public HttpHostConnectException(final HttpHost host, final ConnectException cause) {
+ super("Connection to " + host + " refused");
+ this.host = host;
+ initCause(cause);
+ }
+
+ public HttpHost getHost() {
+ return this.host;
+ }
+
+}
diff --git a/src/org/apache/http/conn/ManagedClientConnection.java b/src/org/apache/http/conn/ManagedClientConnection.java
new file mode 100644
index 0000000..f642cb9
--- /dev/null
+++ b/src/org/apache/http/conn/ManagedClientConnection.java
@@ -0,0 +1,261 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ManagedClientConnection.java $
+ * $Revision: 672969 $
+ * $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 Jun 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpInetConnection;
+import org.apache.http.HttpHost;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+
+import org.apache.http.conn.routing.HttpRoute;
+
+
+
+/**
+ * A client-side connection with advanced connection logic.
+ * Instances are typically obtained from a connection manager.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 672969 $
+ *
+ * @since 4.0
+ */
+public interface ManagedClientConnection extends
+ HttpClientConnection, HttpInetConnection, ConnectionReleaseTrigger {
+
+
+ /**
+ * Indicates whether this connection is secure.
+ * The return value is well-defined only while the connection is open.
+ * It may change even while the connection is open.
+ *
+ * @return <code>true</code> if this connection is secure,
+ * <code>false</code> otherwise
+ */
+ boolean isSecure()
+ ;
+
+
+ /**
+ * Obtains the current route of this connection.
+ *
+ * @return the route established so far, or
+ * <code>null</code> if not connected
+ */
+ HttpRoute getRoute()
+ ;
+
+
+ /**
+ * Obtains the SSL session of the underlying connection, if any.
+ * If this connection is open, and the underlying socket is an
+ * {@link javax.net.ssl.SSLSocket SSLSocket}, the SSL session of
+ * that socket is obtained. This is a potentially blocking operation.
+ * <br/>
+ * <b>Note:</b> Whether the underlying socket is an SSL socket
+ * can not necessarily be determined via {@link #isSecure}.
+ * Plain sockets may be considered secure, for example if they are
+ * connected to a known host in the same network segment.
+ * On the other hand, SSL sockets may be considered insecure,
+ * for example depending on the chosen cipher suite.
+ *
+ * @return the underlying SSL session if available,
+ * <code>null</code> otherwise
+ */
+ SSLSession getSSLSession()
+ ;
+
+
+ /**
+ * Opens this connection according to the given route.
+ *
+ * @param route the route along which to open. It will be opened to
+ * the first proxy if present, or directly to the target.
+ * @param context the context for opening this connection
+ * @param params the parameters for opening this connection
+ *
+ * @throws IOException in case of a problem
+ */
+ void open(HttpRoute route, HttpContext context, HttpParams params)
+ throws IOException
+ ;
+
+
+ /**
+ * Indicates that a tunnel to the target has been established.
+ * The route is the one previously passed to {@link #open open}.
+ * Subsequently, {@link #layerProtocol layerProtocol} can be called
+ * to layer the TLS/SSL protocol on top of the tunnelled connection.
+ * <br/>
+ * <b>Note:</b> In HttpClient 3, a call to the corresponding method
+ * would automatically trigger the layering of the TLS/SSL protocol.
+ * This is not the case anymore, you can establish a tunnel without
+ * layering a new protocol over the connection.
+ *
+ * @param secure <code>true</code> if the tunnel should be considered
+ * secure, <code>false</code> otherwise
+ * @param params the parameters for tunnelling this connection
+ *
+ * @throws IOException in case of a problem
+ */
+ void tunnelTarget(boolean secure, HttpParams params)
+ throws IOException
+ ;
+
+
+ /**
+ * Indicates that a tunnel to an intermediate proxy has been established.
+ * This is used exclusively for so-called <i>proxy chains</i>, where
+ * a request has to pass through multiple proxies before reaching the
+ * target. In that case, all proxies but the last need to be tunnelled
+ * when establishing the connection. Tunnelling of the last proxy to the
+ * target is optional and would be indicated via {@link #tunnelTarget}.
+ *
+ * @param next the proxy to which the tunnel was established.
+ * This is <i>not</i> the proxy <i>through</i> which
+ * the tunnel was established, but the new end point
+ * of the tunnel. The tunnel does <i>not</i> yet
+ * reach to the target, use {@link #tunnelTarget}
+ * to indicate an end-to-end tunnel.
+ * @param secure <code>true</code> if the connection should be
+ * considered secure, <code>false</code> otherwise
+ * @param params the parameters for tunnelling this connection
+ *
+ * @throws IOException in case of a problem
+ */
+ void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
+ throws IOException
+ ;
+
+
+ /**
+ * Layers a new protocol on top of a {@link #tunnelTarget tunnelled}
+ * connection. This is typically used to create a TLS/SSL connection
+ * through a proxy.
+ * The route is the one previously passed to {@link #open open}.
+ * It is not guaranteed that the layered connection is
+ * {@link #isSecure secure}.
+ *
+ * @param context the context for layering on top of this connection
+ * @param params the parameters for layering on top of this connection
+ *
+ * @throws IOException in case of a problem
+ */
+ void layerProtocol(HttpContext context, HttpParams params)
+ throws IOException
+ ;
+
+
+ /**
+ * Marks this connection as being in a reusable communication state.
+ * The checkpoints for reuseable communication states (in the absence
+ * of pipelining) are before sending a request and after receiving
+ * the response in it's entirety.
+ * The connection will automatically clear the checkpoint when
+ * used for communication. A call to this method indicates that
+ * the next checkpoint has been reached.
+ * <br/>
+ * A reusable communication state is necessary but not sufficient
+ * for the connection to be reused.
+ * A {@link #getRoute route} mismatch, the connection being closed,
+ * or other circumstances might prevent reuse.
+ */
+ void markReusable()
+ ;
+
+
+ /**
+ * Marks this connection as not being in a reusable state.
+ * This can be used immediately before releasing this connection
+ * to prevent it's reuse. Reasons for preventing reuse include
+ * error conditions and the evaluation of a
+ * {@link org.apache.http.ConnectionReuseStrategy reuse strategy}.
+ * <br/>
+ * <b>Note:</b>
+ * It is <i>not</i> necessary to call here before writing to
+ * or reading from this connection. Communication attempts will
+ * automatically unmark the state as non-reusable. It can then
+ * be switched back using {@link #markReusable markReusable}.
+ */
+ void unmarkReusable()
+ ;
+
+
+ /**
+ * Indicates whether this connection is in a reusable communication state.
+ * See {@link #markReusable markReusable} and
+ * {@link #unmarkReusable unmarkReusable} for details.
+ *
+ * @return <code>true</code> if this connection is marked as being in
+ * a reusable communication state,
+ * <code>false</code> otherwise
+ */
+ boolean isMarkedReusable()
+ ;
+
+ /**
+ * Assigns a state object to this connection. Connection managers may make
+ * use of the connection state when allocating persistent connections.
+ *
+ * @param state The state object
+ */
+ void setState(Object state)
+ ;
+
+ /**
+ * Returns the state object associated with this connection.
+ *
+ * @return The state object
+ */
+ Object getState()
+ ;
+
+ /**
+ * Sets the duration that this connection can remain idle before it is
+ * reused. The connection should not be used again if this time elapses. The
+ * idle duration must be reset after each request sent over this connection.
+ * The elapsed time starts counting when the connection is released, which
+ * is typically after the headers (and any response body, if present) is
+ * fully consumed.
+ */
+ void setIdleDuration(long duration, TimeUnit unit);
+
+} // interface ManagedClientConnection
diff --git a/src/org/apache/http/conn/MultihomePlainSocketFactory.java b/src/org/apache/http/conn/MultihomePlainSocketFactory.java
new file mode 100644
index 0000000..e9549ab
--- /dev/null
+++ b/src/org/apache/http/conn/MultihomePlainSocketFactory.java
@@ -0,0 +1,212 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/MultihomePlainSocketFactory.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Arrays;
+
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.SocketFactory;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Socket factory that implements a simple multi-home fail-over on connect failure,
+ * provided the same hostname resolves to multiple {@link InetAddress}es. Please note
+ * the {@link #connectSocket(Socket, String, int, InetAddress, int, HttpParams)}
+ * method cannot be reliably interrupted by closing the socket returned by the
+ * {@link #createSocket()} method.
+ */
+public final class MultihomePlainSocketFactory implements SocketFactory {
+
+ /**
+ * The factory singleton.
+ */
+ private static final
+ MultihomePlainSocketFactory DEFAULT_FACTORY = new MultihomePlainSocketFactory();
+
+ /**
+ * Gets the singleton instance of this class.
+ * @return the one and only plain socket factory
+ */
+ public static MultihomePlainSocketFactory getSocketFactory() {
+ return DEFAULT_FACTORY;
+ }
+
+ /**
+ * Restricted default constructor.
+ */
+ private MultihomePlainSocketFactory() {
+ super();
+ }
+
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket createSocket() {
+ return new Socket();
+ }
+
+ /**
+ * Attempts to connects the socket to any of the {@link InetAddress}es the
+ * given host name resolves to. If connection to all addresses fail, the
+ * last I/O exception is propagated to the caller.
+ *
+ * @param sock socket to connect to any of the given addresses
+ * @param host Host name to connect to
+ * @param port the port to connect to
+ * @param localAddress local address
+ * @param localPort local port
+ * @param params HTTP parameters
+ *
+ * @throws IOException if an error occurs during the connection
+ * @throws SocketTimeoutException if timeout expires before connecting
+ */
+ public Socket connectSocket(Socket sock, String host, int port,
+ InetAddress localAddress, int localPort,
+ HttpParams params)
+ throws IOException {
+
+ if (host == null) {
+ throw new IllegalArgumentException("Target host may not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters may not be null.");
+ }
+
+ if (sock == null)
+ sock = createSocket();
+
+ if ((localAddress != null) || (localPort > 0)) {
+
+ // we need to bind explicitly
+ if (localPort < 0)
+ localPort = 0; // indicates "any"
+
+ InetSocketAddress isa =
+ new InetSocketAddress(localAddress, localPort);
+ sock.bind(isa);
+ }
+
+ int timeout = HttpConnectionParams.getConnectionTimeout(params);
+
+ InetAddress[] inetadrs = InetAddress.getAllByName(host);
+ List<InetAddress> addresses = new ArrayList<InetAddress>(inetadrs.length);
+ addresses.addAll(Arrays.asList(inetadrs));
+ Collections.shuffle(addresses);
+
+ IOException lastEx = null;
+ for (InetAddress address: addresses) {
+ try {
+ sock.connect(new InetSocketAddress(address, port), timeout);
+ break;
+ } catch (SocketTimeoutException ex) {
+ throw ex;
+ } catch (IOException ex) {
+ // create new socket
+ sock = new Socket();
+ // keep the last exception and retry
+ lastEx = ex;
+ }
+ }
+ if (lastEx != null) {
+ throw lastEx;
+ }
+ return sock;
+ } // connectSocket
+
+
+ /**
+ * Checks whether a socket connection is secure.
+ * This factory creates plain socket connections
+ * which are not considered secure.
+ *
+ * @param sock the connected socket
+ *
+ * @return <code>false</code>
+ *
+ * @throws IllegalArgumentException if the argument is invalid
+ */
+ public final boolean isSecure(Socket sock)
+ throws IllegalArgumentException {
+
+ if (sock == null) {
+ throw new IllegalArgumentException("Socket may not be null.");
+ }
+ // This class check assumes that createSocket() calls the constructor
+ // directly. If it was using javax.net.SocketFactory, we couldn't make
+ // an assumption about the socket class here.
+ if (sock.getClass() != Socket.class) {
+ throw new IllegalArgumentException
+ ("Socket not created by this factory.");
+ }
+ // This check is performed last since it calls a method implemented
+ // by the argument object. getClass() is final in java.lang.Object.
+ if (sock.isClosed()) {
+ throw new IllegalArgumentException("Socket is closed.");
+ }
+
+ return false;
+
+ } // isSecure
+
+
+ /**
+ * Compares this factory with an object.
+ * There is only one instance of this class.
+ *
+ * @param obj the object to compare with
+ *
+ * @return iff the argument is this object
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return (obj == this);
+ }
+
+ /**
+ * Obtains a hash code for this object.
+ * All instances of this class have the same hash code.
+ * There is only one instance of this class.
+ */
+ @Override
+ public int hashCode() {
+ return PlainSocketFactory.class.hashCode();
+ }
+
+}
diff --git a/src/org/apache/http/conn/OperatedClientConnection.java b/src/org/apache/http/conn/OperatedClientConnection.java
new file mode 100644
index 0000000..2eda8e9
--- /dev/null
+++ b/src/org/apache/http/conn/OperatedClientConnection.java
@@ -0,0 +1,174 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/OperatedClientConnection.java $
+ * $Revision: 646087 $
+ * $Date: 2008-04-08 14:36:46 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpInetConnection;
+import org.apache.http.params.HttpParams;
+
+
+/**
+ * A client-side connection that relies on outside logic to connect sockets to the
+ * appropriate hosts. It can be operated directly by an application, or through an
+ * {@link ClientConnectionOperator operator}.
+ *
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 646087 $ $Date: 2008-04-08 14:36:46 -0700 (Tue, 08 Apr 2008) $
+ *
+ * @since 4.0
+ */
+public interface OperatedClientConnection
+ extends HttpClientConnection, HttpInetConnection {
+
+ /**
+ * Obtains the target host for this connection.
+ * If the connection is to a proxy but not tunnelled, this is
+ * the proxy. If the connection is tunnelled through a proxy,
+ * this is the target of the tunnel.
+ * <br/>
+ * The return value is well-defined only while the connection is open.
+ * It may change even while the connection is open,
+ * because of an {@link #update update}.
+ *
+ * @return the host to which this connection is opened
+ */
+ HttpHost getTargetHost()
+ ;
+
+ /**
+ * Indicates whether this connection is secure.
+ * The return value is well-defined only while the connection is open.
+ * It may change even while the connection is open,
+ * because of an {@link #update update}.
+ *
+ * @return <code>true</code> if this connection is secure,
+ * <code>false</code> otherwise
+ */
+ boolean isSecure()
+ ;
+
+ /**
+ * Obtains the socket for this connection.
+ * The return value is well-defined only while the connection is open.
+ * It may change even while the connection is open,
+ * because of an {@link #update update}.
+ *
+ * @return the socket for communicating with the
+ * {@link #getTargetHost target host}
+ */
+ Socket getSocket()
+ ;
+
+
+ // There is no getParams(). For the moment, we
+ // do not require connections to store parameters.
+
+
+ /**
+ * Signals that this connection is in the process of being open.
+ * <br/>
+ * By calling this method, you can provide the connection with
+ * the unconnected socket that will be connected before
+ * {@link #openCompleted} is called. This allows
+ * the connection to close that socket if
+ * {@link org.apache.http.HttpConnection#shutdown shutdown}
+ * is called before it is open. Closing the unconnected socket
+ * will interrupt a thread that is blocked on the connect.
+ * Otherwise, that thread will either time out on the connect,
+ * or it returns successfully and then opens this connection
+ * which was just shut down.
+ * <br/>
+ * You also must call {@link #openCompleted} in order to complete
+ * the process
+ *
+ * @param sock the unconnected socket which is about to
+ * be connected.
+ * @param target the target host of this connection
+ */
+ void opening(Socket sock, HttpHost target)
+ throws IOException
+ ;
+
+
+ /**
+ * Signals that the connection has been successfully open.
+ * An attempt to call this method on an open connection will cause
+ * an exception.
+ *
+ * @param secure <code>true</code> if this connection is secure, for
+ * example if an <code>SSLSocket</code> is used, or
+ * <code>false</code> if it is not secure
+ * @param params parameters for this connection. The parameters will
+ * be used when creating dependent objects, for example
+ * to determine buffer sizes.
+ */
+ void openCompleted(boolean secure, HttpParams params)
+ throws IOException
+ ;
+
+
+ /**
+ * Updates this connection.
+ * A connection can be updated only while it is open.
+ * Updates are used for example when a tunnel has been established,
+ * or when a TLS/SSL connection has been layered on top of a plain
+ * socket connection.
+ * <br/>
+ * <b>Note:</b> Updating the connection will <i>not</i> close the
+ * previously used socket. It is the caller's responsibility to close
+ * that socket if it is no longer required.
+ *
+ * @param sock the new socket for communicating with the target host,
+ * or <code>null</code> to continue using the old socket.
+ * If <code>null</code> is passed, helper objects that
+ * depend on the socket should be re-used. In that case,
+ * some changes in the parameters will not take effect.
+ * @param target the new target host of this connection
+ * @param secure <code>true</code> if this connection is now secure,
+ * <code>false</code> if it is not secure
+ * @param params new parameters for this connection
+ */
+ void update(Socket sock, HttpHost target,
+ boolean secure, HttpParams params)
+ throws IOException
+ ;
+
+
+} // interface OperatedClientConnection
diff --git a/src/org/apache/http/conn/package.html b/src/org/apache/http/conn/package.html
new file mode 100644
index 0000000..e0b29cd
--- /dev/null
+++ b/src/org/apache/http/conn/package.html
@@ -0,0 +1,91 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/package.html $
+ * $Revision: 651813 $
+ * $Date: 2008-04-26 03:43:34 -0700 (Sat, 26 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The client-side connection management and handling API
+at the heart of what is referred to as <i>HttpConn</i>.
+This component provides interfaces and implementations for
+opening and managing connections.
+
+<p>
+The lowest layer of connection handling is comprised of
+{@link org.apache.http.conn.OperatedClientConnection OperatedClientConnection}
+and
+{@link org.apache.http.conn.ClientConnectionOperator ClientConnectionOperator}.
+The connection interface extends the core
+{@link org.apache.http.HttpClientConnection HttpClientConnection}
+by operations to set and update a socket.
+An operator encapsulates the logic to open and layer sockets,
+typically using a {@link org.apache.http.conn.scheme.SocketFactory SocketFactory}.
+The socket factory for a protocol
+{@link org.apache.http.conn.scheme.Scheme Scheme}
+such as "http" or "https" can be looked up in a
+{@link org.apache.http.conn.scheme.SchemeRegistry SchemeRegistry}.
+Applications without a need for sophisticated connection management
+can use this layer directly.
+</p>
+
+<p>
+On top of that lies the connection management layer. A
+{@link org.apache.http.conn.ClientConnectionManager ClientConnectionManager}
+internally manages operated connections, but hands out instances of
+{@link org.apache.http.conn.ManagedClientConnection ManagedClientConnection}.
+This interface abstracts from the underlying socket operations and
+provides convenient methods for opening and updating sockets in order
+to establish a {@link org.apache.http.conn.routing.HttpRoute route}.
+The operator is encapsulated by the connection manager and called
+automatically.
+
+<br/>
+
+Connections obtained from a manager have to be returned after use.
+This can be {@link org.apache.http.conn.ConnectionReleaseTrigger triggered}
+on various levels, either by releasing the
+{@link org.apache.http.conn.ManagedClientConnection
+ connection}
+directly, or by calling a method on an
+{@link org.apache.http.conn.BasicManagedEntity entity}
+received from the connection, or by closing the
+{@link org.apache.http.conn.EofSensorInputStream stream}
+from which that entity is being read.
+
+Connection managers will try to keep returned connections alive in
+order to re-use them for subsequent requests along the same route.
+The managed connection interface and all triggers for connection release
+provide methods to enable or disable this behavior.
+</p>
+
+</body>
+</html>
diff --git a/src/org/apache/http/conn/params/ConnConnectionPNames.java b/src/org/apache/http/conn/params/ConnConnectionPNames.java
new file mode 100644
index 0000000..ff1a090
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnConnectionPNames.java
@@ -0,0 +1,65 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnConnectionPNames.java $
+ * $Revision: 576068 $
+ * $Date: 2007-09-16 03:25:01 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+
+/**
+ * Parameter names for connections in HttpConn.
+ *
+ * @version $Revision: 576068 $
+ *
+ * @since 4.0
+ */
+public interface ConnConnectionPNames {
+
+
+ /**
+ * Defines the maximum number of ignorable lines before we expect
+ * a HTTP response's status line.
+ * <p>
+ * With HTTP/1.1 persistent connections, the problem arises that
+ * broken scripts could return a wrong Content-Length
+ * (there are more bytes sent than specified).
+ * Unfortunately, in some cases, this cannot be detected after the
+ * bad response, but only before the next one.
+ * So HttpClient must be able to skip those surplus lines this way.
+ * </p>
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * 0 disallows all garbage/empty lines before the status line.
+ * Use {@link java.lang.Integer#MAX_VALUE} for unlimited
+ * (default in lenient mode).
+ * </p>
+ */
+ public static final String MAX_STATUS_LINE_GARBAGE = "http.connection.max-status-line-garbage";
+
+
+}
diff --git a/src/org/apache/http/conn/params/ConnConnectionParamBean.java b/src/org/apache/http/conn/params/ConnConnectionParamBean.java
new file mode 100644
index 0000000..094b152
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnConnectionParamBean.java
@@ -0,0 +1,55 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnConnectionParamBean.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+import org.apache.http.params.HttpAbstractParamBean;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Allows for setting parameters relating to connections on
+ * {@link HttpParams}. This class ensures that the values set on the params
+ * are type-safe.
+ */
+public class ConnConnectionParamBean extends HttpAbstractParamBean {
+
+ public ConnConnectionParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ /**
+ * @see ConnConnectionPNames#MAX_STATUS_LINE_GARBAGE
+ */
+ public void setMaxStatusLineGarbage (final int maxStatusLineGarbage) {
+ params.setIntParameter(ConnConnectionPNames.MAX_STATUS_LINE_GARBAGE, maxStatusLineGarbage);
+ }
+
+}
diff --git a/src/org/apache/http/conn/params/ConnManagerPNames.java b/src/org/apache/http/conn/params/ConnManagerPNames.java
new file mode 100644
index 0000000..1184b12
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnManagerPNames.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnManagerPNames.java $
+ * $Revision: 658781 $
+ * $Date: 2008-05-21 10:42:13 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+
+/**
+ * Parameter names for connection managers in HttpConn.
+ *
+ * @version $Revision: 658781 $
+ *
+ * @since 4.0
+ */
+public interface ConnManagerPNames {
+
+ /**
+ * Defines the timeout in milliseconds used when retrieving an instance of
+ * {@link org.apache.http.conn.ManagedClientConnection} from the
+ * {@link org.apache.http.conn.ClientConnectionManager}.
+ * <p>
+ * This parameter expects a value of type {@link Long}.
+ * </p>
+ */
+ public static final String TIMEOUT = "http.conn-manager.timeout";
+
+ /**
+ * Defines the maximum number of connections per route.
+ * This limit is interpreted by client connection managers
+ * and applies to individual manager instances.
+ * <p>
+ * This parameter expects a value of type {@link ConnPerRoute}.
+ * </p>
+ */
+ public static final String MAX_CONNECTIONS_PER_ROUTE = "http.conn-manager.max-per-route";
+
+ /**
+ * Defines the maximum number of connections in total.
+ * This limit is interpreted by client connection managers
+ * and applies to individual manager instances.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String MAX_TOTAL_CONNECTIONS = "http.conn-manager.max-total";
+
+}
diff --git a/src/org/apache/http/conn/params/ConnManagerParamBean.java b/src/org/apache/http/conn/params/ConnManagerParamBean.java
new file mode 100644
index 0000000..830b7bf
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnManagerParamBean.java
@@ -0,0 +1,62 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnManagerParamBean.java $
+ * $Revision: 658781 $
+ * $Date: 2008-05-21 10:42:13 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+import org.apache.http.params.HttpAbstractParamBean;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Allows for setting parameters relating to connection managers on
+ * {@link HttpParams}. This class ensures that the values set on the params
+ * are type-safe.
+ */
+public class ConnManagerParamBean extends HttpAbstractParamBean {
+
+ public ConnManagerParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ public void setTimeout (final long timeout) {
+ params.setLongParameter(ConnManagerPNames.TIMEOUT, timeout);
+ }
+
+ /** @see ConnManagerPNames#MAX_TOTAL_CONNECTIONS */
+ public void setMaxTotalConnections (final int maxConnections) {
+ params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, maxConnections);
+ }
+
+ /** @see ConnManagerPNames#MAX_CONNECTIONS_PER_ROUTE */
+ public void setConnectionsPerRoute(final ConnPerRouteBean connPerRoute) {
+ params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, connPerRoute);
+ }
+
+}
diff --git a/src/org/apache/http/conn/params/ConnManagerParams.java b/src/org/apache/http/conn/params/ConnManagerParams.java
new file mode 100644
index 0000000..c6e042e
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnManagerParams.java
@@ -0,0 +1,169 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnManagerParams.java $
+ * $Revision: 658785 $
+ * $Date: 2008-05-21 10:47:40 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.params.HttpParams;
+
+/**
+ * This class represents a collection of HTTP protocol parameters applicable
+ * to client-side
+ * {@link org.apache.http.conn.ClientConnectionManager connection managers}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author Michael Becke
+ *
+ * @version $Revision: 658785 $
+ *
+ * @since 4.0
+ *
+ * @see ConnManagerPNames
+ */
+public final class ConnManagerParams implements ConnManagerPNames {
+
+ /** The default maximum number of connections allowed overall */
+ public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;
+
+ /**
+ * Returns the timeout in milliseconds used when retrieving a
+ * {@link org.apache.http.conn.ManagedClientConnection} from the
+ * {@link org.apache.http.conn.ClientConnectionManager}.
+ *
+ * @return timeout in milliseconds.
+ */
+ public static long getTimeout(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getLongParameter(TIMEOUT, 0);
+ }
+
+ /**
+ * Sets the timeout in milliseconds used when retrieving a
+ * {@link org.apache.http.conn.ManagedClientConnection} from the
+ * {@link org.apache.http.conn.ClientConnectionManager}.
+ *
+ * @param timeout the timeout in milliseconds
+ */
+ public static void setTimeout(final HttpParams params, long timeout) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setLongParameter(TIMEOUT, timeout);
+ }
+
+ /** The default maximum number of connections allowed per host */
+ private static final ConnPerRoute DEFAULT_CONN_PER_ROUTE = new ConnPerRoute() {
+
+ public int getMaxForRoute(HttpRoute route) {
+ return ConnPerRouteBean.DEFAULT_MAX_CONNECTIONS_PER_ROUTE;
+ }
+
+ };
+
+ /**
+ * Sets lookup interface for maximum number of connections allowed per route.
+ *
+ * @param params HTTP parameters
+ * @param connPerRoute lookup interface for maximum number of connections allowed
+ * per route
+ *
+ * @see ConnManagerPNames#MAX_CONNECTIONS_PER_ROUTE
+ */
+ public static void setMaxConnectionsPerRoute(final HttpParams params,
+ final ConnPerRoute connPerRoute) {
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("HTTP parameters must not be null.");
+ }
+ params.setParameter(MAX_CONNECTIONS_PER_ROUTE, connPerRoute);
+ }
+
+ /**
+ * Returns lookup interface for maximum number of connections allowed per route.
+ *
+ * @param params HTTP parameters
+ *
+ * @return lookup interface for maximum number of connections allowed per route.
+ *
+ * @see ConnManagerPNames#MAX_CONNECTIONS_PER_ROUTE
+ */
+ public static ConnPerRoute getMaxConnectionsPerRoute(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("HTTP parameters must not be null.");
+ }
+ ConnPerRoute connPerRoute = (ConnPerRoute) params.getParameter(MAX_CONNECTIONS_PER_ROUTE);
+ if (connPerRoute == null) {
+ connPerRoute = DEFAULT_CONN_PER_ROUTE;
+ }
+ return connPerRoute;
+ }
+
+
+ /**
+ * Sets the maximum number of connections allowed.
+ *
+ * @param params HTTP parameters
+ * @param maxTotalConnections The maximum number of connections allowed.
+ *
+ * @see ConnManagerPNames#MAX_TOTAL_CONNECTIONS
+ */
+ public static void setMaxTotalConnections(
+ final HttpParams params,
+ int maxTotalConnections) {
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("HTTP parameters must not be null.");
+ }
+ params.setIntParameter(MAX_TOTAL_CONNECTIONS, maxTotalConnections);
+ }
+
+ /**
+ * Gets the maximum number of connections allowed.
+ *
+ * @param params HTTP parameters
+ *
+ * @return The maximum number of connections allowed.
+ *
+ * @see ConnManagerPNames#MAX_TOTAL_CONNECTIONS
+ */
+ public static int getMaxTotalConnections(
+ final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("HTTP parameters must not be null.");
+ }
+ return params.getIntParameter(MAX_TOTAL_CONNECTIONS, DEFAULT_MAX_TOTAL_CONNECTIONS);
+ }
+
+
+}
diff --git a/src/org/apache/http/conn/params/ConnPerRoute.java b/src/org/apache/http/conn/params/ConnPerRoute.java
new file mode 100644
index 0000000..abff04e
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnPerRoute.java
@@ -0,0 +1,51 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnPerRoute.java $
+ * $Revision: 651813 $
+ * $Date: 2008-04-26 03:43:34 -0700 (Sat, 26 Apr 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+import org.apache.http.conn.routing.HttpRoute;
+
+/**
+ * This interface is intended for looking up maximum number of connections
+ * allowed for for a given route. This class can be used by pooling
+ * {@link org.apache.http.conn.ClientConnectionManager connection managers} for
+ * a fine-grained control of connections on a per route basis.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 651813 $
+ *
+ * @since 4.0
+ */
+public interface ConnPerRoute {
+
+ int getMaxForRoute(HttpRoute route);
+
+}
diff --git a/src/org/apache/http/conn/params/ConnPerRouteBean.java b/src/org/apache/http/conn/params/ConnPerRouteBean.java
new file mode 100644
index 0000000..c6a36e3
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnPerRouteBean.java
@@ -0,0 +1,114 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnPerRouteBean.java $
+ * $Revision: 652947 $
+ * $Date: 2008-05-02 16:15:40 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.http.conn.routing.HttpRoute;
+
+/**
+ * This class maintains a map of HTTP routes to maximum number of connections allowed
+ * for those routes. This class can be used by pooling
+ * {@link org.apache.http.conn.ClientConnectionManager connection managers} for
+ * a fine-grained control of connections on a per route basis.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 652947 $
+ *
+ * @since 4.0
+ */
+public final class ConnPerRouteBean implements ConnPerRoute {
+
+ /** The default maximum number of connections allowed per host */
+ public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2; // Per RFC 2616 sec 8.1.4
+
+ private final Map<HttpRoute, Integer> maxPerHostMap;
+
+ private int defaultMax;
+
+ public ConnPerRouteBean(int defaultMax) {
+ super();
+ this.maxPerHostMap = new HashMap<HttpRoute, Integer>();
+ setDefaultMaxPerRoute(defaultMax);
+ }
+
+ public ConnPerRouteBean() {
+ this(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
+ }
+
+ public int getDefaultMax() {
+ return this.defaultMax;
+ }
+
+ public void setDefaultMaxPerRoute(int max) {
+ if (max < 1) {
+ throw new IllegalArgumentException
+ ("The maximum must be greater than 0.");
+ }
+ this.defaultMax = max;
+ }
+
+ public void setMaxForRoute(final HttpRoute route, int max) {
+ if (route == null) {
+ throw new IllegalArgumentException
+ ("HTTP route may not be null.");
+ }
+ if (max < 1) {
+ throw new IllegalArgumentException
+ ("The maximum must be greater than 0.");
+ }
+ this.maxPerHostMap.put(route, Integer.valueOf(max));
+ }
+
+ public int getMaxForRoute(final HttpRoute route) {
+ if (route == null) {
+ throw new IllegalArgumentException
+ ("HTTP route may not be null.");
+ }
+ Integer max = this.maxPerHostMap.get(route);
+ if (max != null) {
+ return max.intValue();
+ } else {
+ return this.defaultMax;
+ }
+ }
+
+ public void setMaxForRoutes(final Map<HttpRoute, Integer> map) {
+ if (map == null) {
+ return;
+ }
+ this.maxPerHostMap.clear();
+ this.maxPerHostMap.putAll(map);
+ }
+
+}
diff --git a/src/org/apache/http/conn/params/ConnRoutePNames.java b/src/org/apache/http/conn/params/ConnRoutePNames.java
new file mode 100644
index 0000000..f9d42db
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnRoutePNames.java
@@ -0,0 +1,84 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnRoutePNames.java $
+ * $Revision: 613656 $
+ * $Date: 2008-01-20 11:06:56 -0800 (Sun, 20 Jan 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+/**
+ * Parameter names for routing in HttpConn.
+ *
+ * @version $Revision: 613656 $
+ *
+ * @since 4.0
+ */
+public interface ConnRoutePNames {
+
+ /**
+ * Parameter for the default proxy.
+ * The default value will be used by some
+ * {@link org.apache.http.conn.routing.HttpRoutePlanner HttpRoutePlanner}
+ * implementations, in particular the default implementation.
+ * <p>
+ * This parameter expects a value of type {@link org.apache.http.HttpHost}.
+ * </p>
+ */
+ public static final String DEFAULT_PROXY = "http.route.default-proxy";
+
+
+ /**
+ * Parameter for the local address.
+ * On machines with multiple network interfaces, this parameter
+ * can be used to select the network interface from which the
+ * connection originates.
+ * It will be interpreted by the standard
+ * {@link org.apache.http.conn.routing.HttpRoutePlanner HttpRoutePlanner}
+ * implementations, in particular the default implementation.
+ * <p>
+ * This parameter expects a value of type {@link java.net.InetAddress}.
+ * </p>
+ */
+ public static final String LOCAL_ADDRESS = "http.route.local-address";
+
+
+ /**
+ * Parameter for an forced route.
+ * The forced route will be interpreted by the standard
+ * {@link org.apache.http.conn.routing.HttpRoutePlanner HttpRoutePlanner}
+ * implementations.
+ * Instead of computing a route, the given forced route will be
+ * returned, even if it points to the wrong target host.
+ * <p>
+ * This parameter expects a value of type
+ * {@link org.apache.http.conn.routing.HttpRoute HttpRoute}.
+ * </p>
+ */
+ public static final String FORCED_ROUTE = "http.route.forced-route";
+
+}
+
diff --git a/src/org/apache/http/conn/params/ConnRouteParamBean.java b/src/org/apache/http/conn/params/ConnRouteParamBean.java
new file mode 100644
index 0000000..9464c02
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnRouteParamBean.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnRouteParamBean.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.params.HttpAbstractParamBean;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Allows for setting parameters relating to connection routes on
+ * {@link HttpParams}. This class ensures that the values set on the params
+ * are type-safe.
+ */
+public class ConnRouteParamBean extends HttpAbstractParamBean {
+
+ public ConnRouteParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ /** @see ConnRoutePNames#DEFAULT_PROXY */
+ public void setDefaultProxy (final HttpHost defaultProxy) {
+ params.setParameter(ConnRoutePNames.DEFAULT_PROXY, defaultProxy);
+ }
+
+ /** @see ConnRoutePNames#LOCAL_ADDRESS */
+ public void setLocalAddress (final InetAddress address) {
+ params.setParameter(ConnRoutePNames.LOCAL_ADDRESS, address);
+ }
+
+ /** @see ConnRoutePNames#FORCED_ROUTE */
+ public void setForcedRoute (final HttpRoute route) {
+ params.setParameter(ConnRoutePNames.FORCED_ROUTE, route);
+ }
+
+}
diff --git a/src/org/apache/http/conn/params/ConnRouteParams.java b/src/org/apache/http/conn/params/ConnRouteParams.java
new file mode 100644
index 0000000..2fa1654
--- /dev/null
+++ b/src/org/apache/http/conn/params/ConnRouteParams.java
@@ -0,0 +1,203 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/ConnRouteParams.java $
+ * $Revision: 658785 $
+ * $Date: 2008-05-21 10:47:40 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.params;
+
+
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+import org.apache.http.params.HttpParams;
+import org.apache.http.conn.routing.HttpRoute;
+
+
+
+/**
+ * An adaptor for accessing route related parameters in {@link HttpParams}.
+ * See {@link ConnRoutePNames} for parameter name definitions.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 658785 $
+ *
+ * @since 4.0
+ */
+public class ConnRouteParams implements ConnRoutePNames {
+
+ /**
+ * A special value indicating "no host".
+ * This relies on a nonsense scheme name to avoid conflicts
+ * with actual hosts. Note that this is a <i>valid</i> host.
+ */
+ public static final HttpHost NO_HOST =
+ new HttpHost("127.0.0.255", 0, "no-host");
+
+ /**
+ * A special value indicating "no route".
+ * This is a route with {@link #NO_HOST} as the target.
+ */
+ public static final HttpRoute NO_ROUTE = new HttpRoute(NO_HOST);
+
+
+ /** Disabled default constructor. */
+ private ConnRouteParams() {
+ // no body
+ }
+
+
+ /**
+ * Obtains the {@link ConnRoutePNames#DEFAULT_PROXY DEFAULT_PROXY}
+ * parameter value.
+ * {@link #NO_HOST} will be mapped to <code>null</code>,
+ * to allow unsetting in a hierarchy.
+ *
+ * @param params the parameters in which to look up
+ *
+ * @return the default proxy set in the argument parameters, or
+ * <code>null</code> if not set
+ */
+ public static HttpHost getDefaultProxy(HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters must not be null.");
+ }
+ HttpHost proxy = (HttpHost)
+ params.getParameter(DEFAULT_PROXY);
+ if ((proxy != null) && NO_HOST.equals(proxy)) {
+ // value is explicitly unset
+ proxy = null;
+ }
+ return proxy;
+ }
+
+
+ /**
+ * Sets the {@link ConnRoutePNames#DEFAULT_PROXY DEFAULT_PROXY}
+ * parameter value.
+ *
+ * @param params the parameters in which to set the value
+ * @param proxy the value to set, may be <code>null</code>.
+ * Note that {@link #NO_HOST} will be mapped to
+ * <code>null</code> by {@link #getDefaultProxy},
+ * to allow for explicit unsetting in hierarchies.
+ */
+ public static void setDefaultProxy(HttpParams params,
+ HttpHost proxy) {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters must not be null.");
+ }
+ params.setParameter(DEFAULT_PROXY, proxy);
+ }
+
+
+ /**
+ * Obtains the {@link ConnRoutePNames#FORCED_ROUTE FORCED_ROUTE}
+ * parameter value.
+ * {@link #NO_ROUTE} will be mapped to <code>null</code>,
+ * to allow unsetting in a hierarchy.
+ *
+ * @param params the parameters in which to look up
+ *
+ * @return the forced route set in the argument parameters, or
+ * <code>null</code> if not set
+ */
+ public static HttpRoute getForcedRoute(HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters must not be null.");
+ }
+ HttpRoute route = (HttpRoute)
+ params.getParameter(FORCED_ROUTE);
+ if ((route != null) && NO_ROUTE.equals(route)) {
+ // value is explicitly unset
+ route = null;
+ }
+ return route;
+ }
+
+
+ /**
+ * Sets the {@link ConnRoutePNames#FORCED_ROUTE FORCED_ROUTE}
+ * parameter value.
+ *
+ * @param params the parameters in which to set the value
+ * @param route the value to set, may be <code>null</code>.
+ * Note that {@link #NO_ROUTE} will be mapped to
+ * <code>null</code> by {@link #getForcedRoute},
+ * to allow for explicit unsetting in hierarchies.
+ */
+ public static void setForcedRoute(HttpParams params,
+ HttpRoute route) {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters must not be null.");
+ }
+ params.setParameter(FORCED_ROUTE, route);
+ }
+
+
+ /**
+ * Obtains the {@link ConnRoutePNames#LOCAL_ADDRESS LOCAL_ADDRESS}
+ * parameter value.
+ * There is no special value that would automatically be mapped to
+ * <code>null</code>. You can use the wildcard address (0.0.0.0 for IPv4,
+ * :: for IPv6) to override a specific local address in a hierarchy.
+ *
+ * @param params the parameters in which to look up
+ *
+ * @return the local address set in the argument parameters, or
+ * <code>null</code> if not set
+ */
+ public static InetAddress getLocalAddress(HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters must not be null.");
+ }
+ InetAddress local = (InetAddress)
+ params.getParameter(LOCAL_ADDRESS);
+ // no explicit unsetting
+ return local;
+ }
+
+
+ /**
+ * Sets the {@link ConnRoutePNames#LOCAL_ADDRESS LOCAL_ADDRESS}
+ * parameter value.
+ *
+ * @param params the parameters in which to set the value
+ * @param local the value to set, may be <code>null</code>
+ */
+ public static void setLocalAddress(HttpParams params,
+ InetAddress local) {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters must not be null.");
+ }
+ params.setParameter(LOCAL_ADDRESS, local);
+ }
+
+}
+
diff --git a/src/org/apache/http/conn/params/package.html b/src/org/apache/http/conn/params/package.html
new file mode 100644
index 0000000..9b80420
--- /dev/null
+++ b/src/org/apache/http/conn/params/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/params/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Parameters for configuring <i>HttpConn</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/conn/routing/BasicRouteDirector.java b/src/org/apache/http/conn/routing/BasicRouteDirector.java
new file mode 100644
index 0000000..a3714ec
--- /dev/null
+++ b/src/org/apache/http/conn/routing/BasicRouteDirector.java
@@ -0,0 +1,181 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/BasicRouteDirector.java $
+ * $Revision: 620255 $
+ * $Date: 2008-02-10 02:23:55 -0800 (Sun, 10 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.routing;
+
+
+
+/**
+ * Basic implementation of an {@link HttpRouteDirector HttpRouteDirector}.
+ * This implementation is stateless and therefore thread-safe.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 620255 $
+ *
+ * @since 4.0
+ */
+public class BasicRouteDirector implements HttpRouteDirector {
+
+ // public default constructor
+
+
+ /**
+ * Provides the next step.
+ *
+ * @param plan the planned route
+ * @param fact the currently established route, or
+ * <code>null</code> if nothing is established
+ *
+ * @return one of the constants defined in this class, indicating
+ * either the next step to perform, or success, or failure.
+ * 0 is for success, a negative value for failure.
+ */
+ public int nextStep(RouteInfo plan, RouteInfo fact) {
+ if (plan == null) {
+ throw new IllegalArgumentException
+ ("Planned route may not be null.");
+ }
+
+ int step = UNREACHABLE;
+
+ if ((fact == null) || (fact.getHopCount() < 1))
+ step = firstStep(plan);
+ else if (plan.getHopCount() > 1)
+ step = proxiedStep(plan, fact);
+ else
+ step = directStep(plan, fact);
+
+ return step;
+
+ } // nextStep
+
+
+ /**
+ * Determines the first step to establish a route.
+ *
+ * @param plan the planned route
+ *
+ * @return the first step
+ */
+ protected int firstStep(RouteInfo plan) {
+
+ return (plan.getHopCount() > 1) ?
+ CONNECT_PROXY : CONNECT_TARGET;
+ }
+
+
+ /**
+ * Determines the next step to establish a direct connection.
+ *
+ * @param plan the planned route
+ * @param fact the currently established route
+ *
+ * @return one of the constants defined in this class, indicating
+ * either the next step to perform, or success, or failure
+ */
+ protected int directStep(RouteInfo plan, RouteInfo fact) {
+
+ if (fact.getHopCount() > 1)
+ return UNREACHABLE;
+ if (!plan.getTargetHost().equals(fact.getTargetHost()))
+ return UNREACHABLE;
+ // If the security is too low, we could now suggest to layer
+ // a secure protocol on the direct connection. Layering on direct
+ // connections has not been supported in HttpClient 3.x, we don't
+ // consider it here until there is a real-life use case for it.
+
+ // Should we tolerate if security is better than planned?
+ // (plan.isSecure() && !fact.isSecure())
+ if (plan.isSecure() != fact.isSecure())
+ return UNREACHABLE;
+
+ // Local address has to match only if the plan specifies one.
+ if ((plan.getLocalAddress() != null) &&
+ !plan.getLocalAddress().equals(fact.getLocalAddress())
+ )
+ return UNREACHABLE;
+
+ return COMPLETE;
+ }
+
+
+ /**
+ * Determines the next step to establish a connection via proxy.
+ *
+ * @param plan the planned route
+ * @param fact the currently established route
+ *
+ * @return one of the constants defined in this class, indicating
+ * either the next step to perform, or success, or failure
+ */
+ protected int proxiedStep(RouteInfo plan, RouteInfo fact) {
+
+ if (fact.getHopCount() <= 1)
+ return UNREACHABLE;
+ if (!plan.getTargetHost().equals(fact.getTargetHost()))
+ return UNREACHABLE;
+ final int phc = plan.getHopCount();
+ final int fhc = fact.getHopCount();
+ if (phc < fhc)
+ return UNREACHABLE;
+
+ for (int i=0; i<fhc-1; i++) {
+ if (!plan.getHopTarget(i).equals(fact.getHopTarget(i)))
+ return UNREACHABLE;
+ }
+ // now we know that the target matches and proxies so far are the same
+ if (phc > fhc)
+ return TUNNEL_PROXY; // need to extend the proxy chain
+
+ // proxy chain and target are the same, check tunnelling and layering
+ if ((fact.isTunnelled() && !plan.isTunnelled()) ||
+ (fact.isLayered() && !plan.isLayered()))
+ return UNREACHABLE;
+
+ if (plan.isTunnelled() && !fact.isTunnelled())
+ return TUNNEL_TARGET;
+ if (plan.isLayered() && !fact.isLayered())
+ return LAYER_PROTOCOL;
+
+ // tunnel and layering are the same, remains to check the security
+ // Should we tolerate if security is better than planned?
+ // (plan.isSecure() && !fact.isSecure())
+ if (plan.isSecure() != fact.isSecure())
+ return UNREACHABLE;
+
+ return COMPLETE;
+ }
+
+
+} // class BasicRouteDirector
diff --git a/src/org/apache/http/conn/routing/HttpRoute.java b/src/org/apache/http/conn/routing/HttpRoute.java
new file mode 100644
index 0000000..1e870b8
--- /dev/null
+++ b/src/org/apache/http/conn/routing/HttpRoute.java
@@ -0,0 +1,443 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/HttpRoute.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.routing;
+
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+
+/**
+ * The route for a request.
+ * Instances of this class are unmodifiable and therefore suitable
+ * for use as lookup keys.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 653041 $
+ *
+ * @since 4.0
+ */
+public final class HttpRoute implements RouteInfo, Cloneable {
+
+ /** The target host to connect to. */
+ private final HttpHost targetHost;
+
+ /**
+ * The local address to connect from.
+ * <code>null</code> indicates that the default should be used.
+ */
+ private final InetAddress localAddress;
+
+ /** The proxy servers, if any. */
+ private final HttpHost[] proxyChain;
+
+ /** Whether the the route is tunnelled through the proxy. */
+ private final TunnelType tunnelled;
+
+ /** Whether the route is layered. */
+ private final LayerType layered;
+
+ /** Whether the route is (supposed to be) secure. */
+ private final boolean secure;
+
+
+ /**
+ * Internal, fully-specified constructor.
+ * This constructor does <i>not</i> clone the proxy chain array,
+ * nor test it for <code>null</code> elements. This conversion and
+ * check is the responsibility of the public constructors.
+ * The order of arguments here is different from the similar public
+ * constructor, as required by Java.
+ *
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ * @param target the host to which to route
+ * @param proxies the proxy chain to use, or
+ * <code>null</code> for a direct route
+ * @param secure <code>true</code> if the route is (to be) secure,
+ * <code>false</code> otherwise
+ * @param tunnelled the tunnel type of this route, or
+ * <code>null</code> for PLAIN
+ * @param layered the layering type of this route, or
+ * <code>null</code> for PLAIN
+ */
+ private HttpRoute(InetAddress local,
+ HttpHost target, HttpHost[] proxies,
+ boolean secure,
+ TunnelType tunnelled, LayerType layered) {
+ if (target == null) {
+ throw new IllegalArgumentException
+ ("Target host may not be null.");
+ }
+ if ((tunnelled == TunnelType.TUNNELLED) && (proxies == null)) {
+ throw new IllegalArgumentException
+ ("Proxy required if tunnelled.");
+ }
+
+ // tunnelled is already checked above, that is in line with the default
+ if (tunnelled == null)
+ tunnelled = TunnelType.PLAIN;
+ if (layered == null)
+ layered = LayerType.PLAIN;
+
+ this.targetHost = target;
+ this.localAddress = local;
+ this.proxyChain = proxies;
+ this.secure = secure;
+ this.tunnelled = tunnelled;
+ this.layered = layered;
+ }
+
+
+ /**
+ * Creates a new route with all attributes specified explicitly.
+ *
+ * @param target the host to which to route
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ * @param proxies the proxy chain to use, or
+ * <code>null</code> for a direct route
+ * @param secure <code>true</code> if the route is (to be) secure,
+ * <code>false</code> otherwise
+ * @param tunnelled the tunnel type of this route
+ * @param layered the layering type of this route
+ */
+ public HttpRoute(HttpHost target, InetAddress local, HttpHost[] proxies,
+ boolean secure, TunnelType tunnelled, LayerType layered) {
+ this(local, target, toChain(proxies), secure, tunnelled, layered);
+ }
+
+
+ /**
+ * Creates a new route with at most one proxy.
+ *
+ * @param target the host to which to route
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ * @param proxy the proxy to use, or
+ * <code>null</code> for a direct route
+ * @param secure <code>true</code> if the route is (to be) secure,
+ * <code>false</code> otherwise
+ * @param tunnelled <code>true</code> if the route is (to be) tunnelled
+ * via the proxy,
+ * <code>false</code> otherwise
+ * @param layered <code>true</code> if the route includes a
+ * layered protocol,
+ * <code>false</code> otherwise
+ */
+ public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
+ boolean secure, TunnelType tunnelled, LayerType layered) {
+ this(local, target, toChain(proxy), secure, tunnelled, layered);
+ }
+
+
+ /**
+ * Creates a new direct route.
+ * That is a route without a proxy.
+ *
+ * @param target the host to which to route
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ * @param secure <code>true</code> if the route is (to be) secure,
+ * <code>false</code> otherwise
+ */
+ public HttpRoute(HttpHost target, InetAddress local, boolean secure) {
+ this(local, target, null, secure, TunnelType.PLAIN, LayerType.PLAIN);
+ }
+
+
+ /**
+ * Creates a new direct insecure route.
+ *
+ * @param target the host to which to route
+ */
+ public HttpRoute(HttpHost target) {
+ this(null, target, null, false, TunnelType.PLAIN, LayerType.PLAIN);
+ }
+
+
+ /**
+ * Creates a new route through a proxy.
+ * When using this constructor, the <code>proxy</code> MUST be given.
+ * For convenience, it is assumed that a secure connection will be
+ * layered over a tunnel through the proxy.
+ *
+ * @param target the host to which to route
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ * @param proxy the proxy to use
+ * @param secure <code>true</code> if the route is (to be) secure,
+ * <code>false</code> otherwise
+ */
+ public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
+ boolean secure) {
+ this(local, target, toChain(proxy), secure,
+ secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
+ secure ? LayerType.LAYERED : LayerType.PLAIN);
+ if (proxy == null) {
+ throw new IllegalArgumentException
+ ("Proxy host may not be null.");
+ }
+ }
+
+
+ /**
+ * Helper to convert a proxy to a proxy chain.
+ *
+ * @param proxy the only proxy in the chain, or <code>null</code>
+ *
+ * @return a proxy chain array, or <code>null</code>
+ */
+ private static HttpHost[] toChain(HttpHost proxy) {
+ if (proxy == null)
+ return null;
+
+ return new HttpHost[]{ proxy };
+ }
+
+
+ /**
+ * Helper to duplicate and check a proxy chain.
+ * An empty proxy chain is converted to <code>null</code>.
+ *
+ * @param proxies the proxy chain to duplicate, or <code>null</code>
+ *
+ * @return a new proxy chain array, or <code>null</code>
+ */
+ private static HttpHost[] toChain(HttpHost[] proxies) {
+ if ((proxies == null) || (proxies.length < 1))
+ return null;
+
+ for (HttpHost proxy : proxies) {
+ if (proxy == null)
+ throw new IllegalArgumentException
+ ("Proxy chain may not contain null elements.");
+ }
+
+ // copy the proxy chain, the traditional way
+ HttpHost[] result = new HttpHost[proxies.length];
+ System.arraycopy(proxies, 0, result, 0, proxies.length);
+
+ return result;
+ }
+
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final HttpHost getTargetHost() {
+ return this.targetHost;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final InetAddress getLocalAddress() {
+ return this.localAddress;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final int getHopCount() {
+ return (proxyChain == null) ? 1 : (proxyChain.length+1);
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final HttpHost getHopTarget(int hop) {
+ if (hop < 0)
+ throw new IllegalArgumentException
+ ("Hop index must not be negative: " + hop);
+ final int hopcount = getHopCount();
+ if (hop >= hopcount)
+ throw new IllegalArgumentException
+ ("Hop index " + hop +
+ " exceeds route length " + hopcount);
+
+ HttpHost result = null;
+ if (hop < hopcount-1)
+ result = this.proxyChain[hop];
+ else
+ result = this.targetHost;
+
+ return result;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final HttpHost getProxyHost() {
+ return (this.proxyChain == null) ? null : this.proxyChain[0];
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final TunnelType getTunnelType() {
+ return this.tunnelled;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isTunnelled() {
+ return (this.tunnelled == TunnelType.TUNNELLED);
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final LayerType getLayerType() {
+ return this.layered;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isLayered() {
+ return (this.layered == LayerType.LAYERED);
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isSecure() {
+ return this.secure;
+ }
+
+
+ /**
+ * Compares this route to another.
+ *
+ * @param o the object to compare with
+ *
+ * @return <code>true</code> if the argument is the same route,
+ * <code>false</code>
+ */
+ @Override
+ public final boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof HttpRoute))
+ return false;
+
+ HttpRoute that = (HttpRoute) o;
+ boolean equal = this.targetHost.equals(that.targetHost);
+ equal &=
+ ( this.localAddress == that.localAddress) ||
+ ((this.localAddress != null) &&
+ this.localAddress.equals(that.localAddress));
+ equal &=
+ ( this.proxyChain == that.proxyChain) ||
+ ((this.proxyChain != null) &&
+ (that.proxyChain != null) &&
+ (this.proxyChain.length == that.proxyChain.length));
+ // comparison of actual proxies follows below
+ equal &=
+ (this.secure == that.secure) &&
+ (this.tunnelled == that.tunnelled) &&
+ (this.layered == that.layered);
+
+ // chain length has been compared above, now check the proxies
+ if (equal && (this.proxyChain != null)) {
+ for (int i=0; equal && (i<this.proxyChain.length); i++)
+ equal = this.proxyChain[i].equals(that.proxyChain[i]);
+ }
+
+ return equal;
+ }
+
+
+ /**
+ * Generates a hash code for this route.
+ *
+ * @return the hash code
+ */
+ @Override
+ public final int hashCode() {
+
+ int hc = this.targetHost.hashCode();
+
+ if (this.localAddress != null)
+ hc ^= localAddress.hashCode();
+ if (this.proxyChain != null) {
+ hc ^= proxyChain.length;
+ for (HttpHost aProxyChain : proxyChain) hc ^= aProxyChain.hashCode();
+ }
+
+ if (this.secure)
+ hc ^= 0x11111111;
+
+ hc ^= this.tunnelled.hashCode();
+ hc ^= this.layered.hashCode();
+
+ return hc;
+ }
+
+
+ /**
+ * Obtains a description of this route.
+ *
+ * @return a human-readable representation of this route
+ */
+ @Override
+ public final String toString() {
+ StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
+
+ cab.append("HttpRoute[");
+ if (this.localAddress != null) {
+ cab.append(this.localAddress);
+ cab.append("->");
+ }
+ cab.append('{');
+ if (this.tunnelled == TunnelType.TUNNELLED)
+ cab.append('t');
+ if (this.layered == LayerType.LAYERED)
+ cab.append('l');
+ if (this.secure)
+ cab.append('s');
+ cab.append("}->");
+ if (this.proxyChain != null) {
+ for (HttpHost aProxyChain : this.proxyChain) {
+ cab.append(aProxyChain);
+ cab.append("->");
+ }
+ }
+ cab.append(this.targetHost);
+ cab.append(']');
+
+ return cab.toString();
+ }
+
+
+ // default implementation of clone() is sufficient
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+
+} // class HttpRoute
diff --git a/src/org/apache/http/conn/routing/HttpRouteDirector.java b/src/org/apache/http/conn/routing/HttpRouteDirector.java
new file mode 100644
index 0000000..8cfcf67
--- /dev/null
+++ b/src/org/apache/http/conn/routing/HttpRouteDirector.java
@@ -0,0 +1,88 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/HttpRouteDirector.java $
+ * $Revision: 620255 $
+ * $Date: 2008-02-10 02:23:55 -0800 (Sun, 10 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.routing;
+
+
+
+/**
+ * Provides directions on establishing a route.
+ * Implementations of this interface compare a planned route with
+ * a tracked route and indicate the next step required.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 620255 $
+ *
+ * @since 4.0
+ */
+public interface HttpRouteDirector {
+
+ /** Indicates that the route can not be established at all. */
+ public final static int UNREACHABLE = -1;
+
+ /** Indicates that the route is complete. */
+ public final static int COMPLETE = 0;
+
+ /** Step: open connection to target. */
+ public final static int CONNECT_TARGET = 1;
+
+ /** Step: open connection to proxy. */
+ public final static int CONNECT_PROXY = 2;
+
+ /** Step: tunnel through proxy to target. */
+ public final static int TUNNEL_TARGET = 3;
+
+ /** Step: tunnel through proxy to other proxy. */
+ public final static int TUNNEL_PROXY = 4;
+
+ /** Step: layer protocol (over tunnel). */
+ public final static int LAYER_PROTOCOL = 5;
+
+
+ /**
+ * Provides the next step.
+ *
+ * @param plan the planned route
+ * @param fact the currently established route, or
+ * <code>null</code> if nothing is established
+ *
+ * @return one of the constants defined in this interface, indicating
+ * either the next step to perform, or success, or failure.
+ * 0 is for success, a negative value for failure.
+ */
+ public int nextStep(RouteInfo plan, RouteInfo fact)
+ ;
+
+
+} // interface HttpRouteDirector
diff --git a/src/org/apache/http/conn/routing/HttpRoutePlanner.java b/src/org/apache/http/conn/routing/HttpRoutePlanner.java
new file mode 100644
index 0000000..489702a
--- /dev/null
+++ b/src/org/apache/http/conn/routing/HttpRoutePlanner.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/HttpRoutePlanner.java $
+ * $Revision: 613654 $
+ * $Date: 2008-01-20 11:00:19 -0800 (Sun, 20 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.routing;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.protocol.HttpContext;
+
+
+
+/**
+ * Encapsulates logic to compute a {@link HttpRoute} to a target host.
+ * Implementations may for example be based on parameters, or on the
+ * standard Java system properties.
+ */
+public interface HttpRoutePlanner {
+
+ /**
+ * Determines the route for a request.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ * @param context the context to use for the subsequent execution.
+ * Implementations may accept <code>null</code>.
+ *
+ * @return the route that the request should take
+ *
+ * @throws HttpException in case of a problem
+ */
+ public HttpRoute determineRoute(HttpHost target,
+ HttpRequest request,
+ HttpContext context)
+ throws HttpException
+ ;
+
+}
diff --git a/src/org/apache/http/conn/routing/RouteInfo.java b/src/org/apache/http/conn/routing/RouteInfo.java
new file mode 100644
index 0000000..3449cb1
--- /dev/null
+++ b/src/org/apache/http/conn/routing/RouteInfo.java
@@ -0,0 +1,194 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/RouteInfo.java $
+ * $Revision: 652200 $
+ * $Date: 2008-04-29 17:22:43 -0700 (Tue, 29 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.routing;
+
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+
+
+/**
+ * Read-only interface for route information.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 652200 $
+ *
+ * @since 4.0
+ */
+public interface RouteInfo {
+
+ /**
+ * The tunnelling type of a route.
+ * Plain routes are established by connecting to the target or
+ * the first proxy.
+ * Tunnelled routes are established by connecting to the first proxy
+ * and tunnelling through all proxies to the target.
+ * Routes without a proxy cannot be tunnelled.
+ */
+ public enum TunnelType { PLAIN, TUNNELLED }
+
+ /**
+ * The layering type of a route.
+ * Plain routes are established by connecting or tunnelling.
+ * Layered routes are established by layering a protocol such as TLS/SSL
+ * over an existing connection.
+ * Protocols can only be layered over a tunnel to the target, or
+ * or over a direct connection without proxies.
+ * <br/>
+ * Layering a protocol
+ * over a direct connection makes little sense, since the connection
+ * could be established with the new protocol in the first place.
+ * But we don't want to exclude that use case.
+ */
+ public enum LayerType { PLAIN, LAYERED }
+
+
+
+ /**
+ * Obtains the target host.
+ *
+ * @return the target host
+ */
+ HttpHost getTargetHost()
+ ;
+
+
+ /**
+ * Obtains the local address to connect from.
+ *
+ * @return the local address,
+ * or <code>null</code>
+ */
+ InetAddress getLocalAddress()
+ ;
+
+
+ /**
+ * Obtains the number of hops in this route.
+ * A direct route has one hop. A route through a proxy has two hops.
+ * A route through a chain of <i>n</i> proxies has <i>n+1</i> hops.
+ *
+ * @return the number of hops in this route
+ */
+ int getHopCount()
+ ;
+
+
+ /**
+ * Obtains the target of a hop in this route.
+ * The target of the last hop is the {@link #getTargetHost target host},
+ * the target of previous hops is the respective proxy in the chain.
+ * For a route through exactly one proxy, target of hop 0 is the proxy
+ * and target of hop 1 is the target host.
+ *
+ * @param hop index of the hop for which to get the target,
+ * 0 for first
+ *
+ * @return the target of the given hop
+ *
+ * @throws IllegalArgumentException
+ * if the argument is negative or not less than
+ * {@link #getHopCount getHopCount()}
+ */
+ HttpHost getHopTarget(int hop)
+ ;
+
+
+ /**
+ * Obtains the first proxy host.
+ *
+ * @return the first proxy in the proxy chain, or
+ * <code>null</code> if this route is direct
+ */
+ HttpHost getProxyHost()
+ ;
+
+
+ /**
+ * Obtains the tunnel type of this route.
+ * If there is a proxy chain, only end-to-end tunnels are considered.
+ *
+ * @return the tunnelling type
+ */
+ TunnelType getTunnelType()
+ ;
+
+
+ /**
+ * Checks whether this route is tunnelled through a proxy.
+ * If there is a proxy chain, only end-to-end tunnels are considered.
+ *
+ * @return <code>true</code> if tunnelled end-to-end through at least
+ * one proxy,
+ * <code>false</code> otherwise
+ */
+ boolean isTunnelled()
+ ;
+
+
+ /**
+ * Obtains the layering type of this route.
+ * In the presence of proxies, only layering over an end-to-end tunnel
+ * is considered.
+ *
+ * @return the layering type
+ */
+ LayerType getLayerType()
+ ;
+
+
+ /**
+ * Checks whether this route includes a layered protocol.
+ * In the presence of proxies, only layering over an end-to-end tunnel
+ * is considered.
+ *
+ * @return <code>true</code> if layered,
+ * <code>false</code> otherwise
+ */
+ boolean isLayered()
+ ;
+
+
+ /**
+ * Checks whether this route is secure.
+ *
+ * @return <code>true</code> if secure,
+ * <code>false</code> otherwise
+ */
+ boolean isSecure()
+ ;
+
+
+} // interface RouteInfo
diff --git a/src/org/apache/http/conn/routing/RouteTracker.java b/src/org/apache/http/conn/routing/RouteTracker.java
new file mode 100644
index 0000000..ba8213e
--- /dev/null
+++ b/src/org/apache/http/conn/routing/RouteTracker.java
@@ -0,0 +1,439 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/RouteTracker.java $
+ * $Revision: 620254 $
+ * $Date: 2008-02-10 02:18:48 -0800 (Sun, 10 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.routing;
+
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+
+
+/**
+ * Helps tracking the steps in establishing a route.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 620254 $
+ *
+ * @since 4.0
+ */
+public final class RouteTracker implements RouteInfo, Cloneable {
+
+ /** The target host to connect to. */
+ private final HttpHost targetHost;
+
+ /**
+ * The local address to connect from.
+ * <code>null</code> indicates that the default should be used.
+ */
+ private final InetAddress localAddress;
+
+ // the attributes above are fixed at construction time
+ // now follow attributes that indicate the established route
+
+ /** Whether the first hop of the route is established. */
+ private boolean connected;
+
+ /** The proxy chain, if any. */
+ private HttpHost[] proxyChain;
+
+ /** Whether the the route is tunnelled end-to-end through proxies. */
+ private TunnelType tunnelled;
+
+ /** Whether the route is layered over a tunnel. */
+ private LayerType layered;
+
+ /** Whether the route is secure. */
+ private boolean secure;
+
+
+ /**
+ * Creates a new route tracker.
+ * The target and origin need to be specified at creation time.
+ *
+ * @param target the host to which to route
+ * @param local the local address to route from, or
+ * <code>null</code> for the default
+ */
+ public RouteTracker(HttpHost target, InetAddress local) {
+ if (target == null) {
+ throw new IllegalArgumentException("Target host may not be null.");
+ }
+ this.targetHost = target;
+ this.localAddress = local;
+ this.tunnelled = TunnelType.PLAIN;
+ this.layered = LayerType.PLAIN;
+ }
+
+
+ /**
+ * Creates a new tracker for the given route.
+ * Only target and origin are taken from the route,
+ * everything else remains to be tracked.
+ *
+ * @param route the route to track
+ */
+ public RouteTracker(HttpRoute route) {
+ this(route.getTargetHost(), route.getLocalAddress());
+ }
+
+
+ /**
+ * Tracks connecting to the target.
+ *
+ * @param secure <code>true</code> if the route is secure,
+ * <code>false</code> otherwise
+ */
+ public final void connectTarget(boolean secure) {
+ if (this.connected) {
+ throw new IllegalStateException("Already connected.");
+ }
+ this.connected = true;
+ this.secure = secure;
+ }
+
+
+ /**
+ * Tracks connecting to the first proxy.
+ *
+ * @param proxy the proxy connected to
+ * @param secure <code>true</code> if the route is secure,
+ * <code>false</code> otherwise
+ */
+ public final void connectProxy(HttpHost proxy, boolean secure) {
+ if (proxy == null) {
+ throw new IllegalArgumentException("Proxy host may not be null.");
+ }
+ if (this.connected) {
+ throw new IllegalStateException("Already connected.");
+ }
+ this.connected = true;
+ this.proxyChain = new HttpHost[]{ proxy };
+ this.secure = secure;
+ }
+
+
+ /**
+ * Tracks tunnelling to the target.
+ *
+ * @param secure <code>true</code> if the route is secure,
+ * <code>false</code> otherwise
+ */
+ public final void tunnelTarget(boolean secure) {
+ if (!this.connected) {
+ throw new IllegalStateException("No tunnel unless connected.");
+ }
+ if (this.proxyChain == null) {
+ throw new IllegalStateException("No tunnel without proxy.");
+ }
+ this.tunnelled = TunnelType.TUNNELLED;
+ this.secure = secure;
+ }
+
+
+ /**
+ * Tracks tunnelling to a proxy in a proxy chain.
+ * This will extend the tracked proxy chain, but it does not mark
+ * the route as tunnelled. Only end-to-end tunnels are considered there.
+ *
+ * @param proxy the proxy tunnelled to
+ * @param secure <code>true</code> if the route is secure,
+ * <code>false</code> otherwise
+ */
+ public final void tunnelProxy(HttpHost proxy, boolean secure) {
+ if (proxy == null) {
+ throw new IllegalArgumentException("Proxy host may not be null.");
+ }
+ if (!this.connected) {
+ throw new IllegalStateException("No tunnel unless connected.");
+ }
+ if (this.proxyChain == null) {
+ throw new IllegalStateException("No proxy tunnel without proxy.");
+ }
+
+ // prepare an extended proxy chain
+ HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
+ System.arraycopy(this.proxyChain, 0,
+ proxies, 0, this.proxyChain.length);
+ proxies[proxies.length-1] = proxy;
+
+ this.proxyChain = proxies;
+ this.secure = secure;
+ }
+
+
+ /**
+ * Tracks layering a protocol.
+ *
+ * @param secure <code>true</code> if the route is secure,
+ * <code>false</code> otherwise
+ */
+ public final void layerProtocol(boolean secure) {
+ // it is possible to layer a protocol over a direct connection,
+ // although this case is probably not considered elsewhere
+ if (!this.connected) {
+ throw new IllegalStateException
+ ("No layered protocol unless connected.");
+ }
+ this.layered = LayerType.LAYERED;
+ this.secure = secure;
+ }
+
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final HttpHost getTargetHost() {
+ return this.targetHost;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final InetAddress getLocalAddress() {
+ return this.localAddress;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final int getHopCount() {
+ int hops = 0;
+ if (this.connected) {
+ if (proxyChain == null)
+ hops = 1;
+ else
+ hops = proxyChain.length + 1;
+ }
+ return hops;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final HttpHost getHopTarget(int hop) {
+ if (hop < 0)
+ throw new IllegalArgumentException
+ ("Hop index must not be negative: " + hop);
+ final int hopcount = getHopCount();
+ if (hop >= hopcount) {
+ throw new IllegalArgumentException
+ ("Hop index " + hop +
+ " exceeds tracked route length " + hopcount +".");
+ }
+
+ HttpHost result = null;
+ if (hop < hopcount-1)
+ result = this.proxyChain[hop];
+ else
+ result = this.targetHost;
+
+ return result;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final HttpHost getProxyHost() {
+ return (this.proxyChain == null) ? null : this.proxyChain[0];
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isConnected() {
+ return this.connected;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final TunnelType getTunnelType() {
+ return this.tunnelled;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isTunnelled() {
+ return (this.tunnelled == TunnelType.TUNNELLED);
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final LayerType getLayerType() {
+ return this.layered;
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isLayered() {
+ return (this.layered == LayerType.LAYERED);
+ }
+
+
+ // non-JavaDoc, see interface RouteInfo
+ public final boolean isSecure() {
+ return this.secure;
+ }
+
+
+ /**
+ * Obtains the tracked route.
+ * If a route has been tracked, it is {@link #isConnected connected}.
+ * If not connected, nothing has been tracked so far.
+ *
+ * @return the tracked route, or
+ * <code>null</code> if nothing has been tracked so far
+ */
+ public final HttpRoute toRoute() {
+ return !this.connected ?
+ null : new HttpRoute(this.targetHost, this.localAddress,
+ this.proxyChain, this.secure,
+ this.tunnelled, this.layered);
+ }
+
+
+ /**
+ * Compares this tracked route to another.
+ *
+ * @param o the object to compare with
+ *
+ * @return <code>true</code> if the argument is the same tracked route,
+ * <code>false</code>
+ */
+ @Override
+ public final boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof RouteTracker))
+ return false;
+
+ RouteTracker that = (RouteTracker) o;
+ boolean equal = this.targetHost.equals(that.targetHost);
+ equal &=
+ ( this.localAddress == that.localAddress) ||
+ ((this.localAddress != null) &&
+ this.localAddress.equals(that.localAddress));
+ equal &=
+ ( this.proxyChain == that.proxyChain) ||
+ ((this.proxyChain != null) &&
+ (that.proxyChain != null) &&
+ (this.proxyChain.length == that.proxyChain.length));
+ // comparison of actual proxies follows below
+ equal &=
+ (this.connected == that.connected) &&
+ (this.secure == that.secure) &&
+ (this.tunnelled == that.tunnelled) &&
+ (this.layered == that.layered);
+
+ // chain length has been compared above, now check the proxies
+ if (equal && (this.proxyChain != null)) {
+ for (int i=0; equal && (i<this.proxyChain.length); i++)
+ equal = this.proxyChain[i].equals(that.proxyChain[i]);
+ }
+
+ return equal;
+ }
+
+
+ /**
+ * Generates a hash code for this tracked route.
+ * Route trackers are modifiable and should therefore not be used
+ * as lookup keys. Use {@link #toRoute toRoute} to obtain an
+ * unmodifiable representation of the tracked route.
+ *
+ * @return the hash code
+ */
+ @Override
+ public final int hashCode() {
+
+ int hc = this.targetHost.hashCode();
+
+ if (this.localAddress != null)
+ hc ^= localAddress.hashCode();
+ if (this.proxyChain != null) {
+ hc ^= proxyChain.length;
+ for (int i=0; i<proxyChain.length; i++)
+ hc ^= proxyChain[i].hashCode();
+ }
+
+ if (this.connected)
+ hc ^= 0x11111111;
+ if (this.secure)
+ hc ^= 0x22222222;
+
+ hc ^= this.tunnelled.hashCode();
+ hc ^= this.layered.hashCode();
+
+ return hc;
+ }
+
+
+ /**
+ * Obtains a description of the tracked route.
+ *
+ * @return a human-readable representation of the tracked route
+ */
+ @Override
+ public final String toString() {
+ StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
+
+ cab.append("RouteTracker[");
+ if (this.localAddress != null) {
+ cab.append(this.localAddress);
+ cab.append("->");
+ }
+ cab.append('{');
+ if (this.connected)
+ cab.append('c');
+ if (this.tunnelled == TunnelType.TUNNELLED)
+ cab.append('t');
+ if (this.layered == LayerType.LAYERED)
+ cab.append('l');
+ if (this.secure)
+ cab.append('s');
+ cab.append("}->");
+ if (this.proxyChain != null) {
+ for (int i=0; i<this.proxyChain.length; i++) {
+ cab.append(this.proxyChain[i]);
+ cab.append("->");
+ }
+ }
+ cab.append(this.targetHost);
+ cab.append(']');
+
+ return cab.toString();
+ }
+
+
+ // default implementation of clone() is sufficient
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+
+} // class RouteTracker
diff --git a/src/org/apache/http/conn/routing/package.html b/src/org/apache/http/conn/routing/package.html
new file mode 100644
index 0000000..b50f97c
--- /dev/null
+++ b/src/org/apache/http/conn/routing/package.html
@@ -0,0 +1,62 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/package.html $
+ * $Revision: 613656 $
+ * $Date: 2008-01-20 11:06:56 -0800 (Sun, 20 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The client-side route representation and tracking API, part of <i>HttpConn</i>.
+
+<p>
+An {@link org.apache.http.conn.routing.HttpRoute HttpRoute}
+is the path along which a request has to be sent to the server.
+The route starts at a local network address and may pass
+through one or more proxies before reaching the target.
+Routes through proxies can be tunnelled, and a layered protocol (TLS/SSL)
+might be put on top of the tunnel.
+The {@link org.apache.http.conn.routing.RouteTracker RouteTracker}
+helps in tracking the steps for establishing a route, while an
+{@link org.apache.http.conn.routing.HttpRouteDirector HttpRouteDirector}
+determines the next step to take.
+</p>
+
+
+<p>
+The {@link org.apache.http.conn.routing.HttpRoutePlanner HttpRoutePlanner}
+is responsible for determining a route to a given target host.
+Implementations must know about proxies to use, and about exemptions
+for hosts that should be contacted directly without a proxy.
+</p>
+
+
+</body>
+</html>
diff --git a/src/org/apache/http/conn/scheme/HostNameResolver.java b/src/org/apache/http/conn/scheme/HostNameResolver.java
new file mode 100644
index 0000000..ca6615c
--- /dev/null
+++ b/src/org/apache/http/conn/scheme/HostNameResolver.java
@@ -0,0 +1,41 @@
+/*
+ * $HeadURL:$
+ * $Revision:$
+ * $Date:$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+public interface HostNameResolver {
+
+ InetAddress resolve (String hostname) throws IOException;
+
+}
diff --git a/src/org/apache/http/conn/scheme/LayeredSocketFactory.java b/src/org/apache/http/conn/scheme/LayeredSocketFactory.java
new file mode 100644
index 0000000..8dc6c6c
--- /dev/null
+++ b/src/org/apache/http/conn/scheme/LayeredSocketFactory.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactory.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * A {@link SocketFactory SocketFactory} for layered sockets (SSL/TLS).
+ * See there for things to consider when implementing a socket factory.
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @since 4.0
+ */
+public interface LayeredSocketFactory extends SocketFactory {
+
+ /**
+ * Returns a socket connected to the given host that is layered over an
+ * existing socket. Used primarily for creating secure sockets through
+ * proxies.
+ *
+ * @param socket the existing socket
+ * @param host the host name/IP
+ * @param port the port on the host
+ * @param autoClose a flag for closing the underling socket when the created
+ * socket is closed
+ *
+ * @return Socket a new socket
+ *
+ * @throws IOException if an I/O error occurs while creating the socket
+ * @throws UnknownHostException if the IP address of the host cannot be
+ * determined
+ */
+ Socket createSocket(
+ Socket socket,
+ String host,
+ int port,
+ boolean autoClose
+ ) throws IOException, UnknownHostException;
+
+}
diff --git a/src/org/apache/http/conn/scheme/PlainSocketFactory.java b/src/org/apache/http/conn/scheme/PlainSocketFactory.java
new file mode 100644
index 0000000..acc13f7
--- /dev/null
+++ b/src/org/apache/http/conn/scheme/PlainSocketFactory.java
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/PlainSocketFactory.java $
+ * $Revision: 659194 $
+ * $Date: 2008-05-22 11:33:47 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * The default class for creating sockets.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author Michael Becke
+ */
+public final class PlainSocketFactory implements SocketFactory {
+
+ /**
+ * The factory singleton.
+ */
+ private static final
+ PlainSocketFactory DEFAULT_FACTORY = new PlainSocketFactory();
+
+ private final HostNameResolver nameResolver;
+
+ /**
+ * Gets the singleton instance of this class.
+ * @return the one and only plain socket factory
+ */
+ public static PlainSocketFactory getSocketFactory() {
+ return DEFAULT_FACTORY;
+ }
+
+ public PlainSocketFactory(final HostNameResolver nameResolver) {
+ super();
+ this.nameResolver = nameResolver;
+ }
+
+
+ public PlainSocketFactory() {
+ this(null);
+ }
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket createSocket() {
+ return new Socket();
+ }
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket connectSocket(Socket sock, String host, int port,
+ InetAddress localAddress, int localPort,
+ HttpParams params)
+ throws IOException {
+
+ if (host == null) {
+ throw new IllegalArgumentException("Target host may not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters may not be null.");
+ }
+
+ if (sock == null)
+ sock = createSocket();
+
+ if ((localAddress != null) || (localPort > 0)) {
+
+ // we need to bind explicitly
+ if (localPort < 0)
+ localPort = 0; // indicates "any"
+
+ InetSocketAddress isa =
+ new InetSocketAddress(localAddress, localPort);
+ sock.bind(isa);
+ }
+
+ int timeout = HttpConnectionParams.getConnectionTimeout(params);
+
+ InetSocketAddress remoteAddress;
+ if (this.nameResolver != null) {
+ remoteAddress = new InetSocketAddress(this.nameResolver.resolve(host), port);
+ } else {
+ remoteAddress = new InetSocketAddress(host, port);
+ }
+
+ sock.connect(remoteAddress, timeout);
+
+ return sock;
+
+ } // connectSocket
+
+
+ /**
+ * Checks whether a socket connection is secure.
+ * This factory creates plain socket connections
+ * which are not considered secure.
+ *
+ * @param sock the connected socket
+ *
+ * @return <code>false</code>
+ *
+ * @throws IllegalArgumentException if the argument is invalid
+ */
+ public final boolean isSecure(Socket sock)
+ throws IllegalArgumentException {
+
+ if (sock == null) {
+ throw new IllegalArgumentException("Socket may not be null.");
+ }
+ // This class check assumes that createSocket() calls the constructor
+ // directly. If it was using javax.net.SocketFactory, we couldn't make
+ // an assumption about the socket class here.
+ if (sock.getClass() != Socket.class) {
+ throw new IllegalArgumentException
+ ("Socket not created by this factory.");
+ }
+ // This check is performed last since it calls a method implemented
+ // by the argument object. getClass() is final in java.lang.Object.
+ if (sock.isClosed()) {
+ throw new IllegalArgumentException("Socket is closed.");
+ }
+
+ return false;
+
+ } // isSecure
+
+
+ /**
+ * Compares this factory with an object.
+ * There is only one instance of this class.
+ *
+ * @param obj the object to compare with
+ *
+ * @return iff the argument is this object
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return (obj == this);
+ }
+
+ /**
+ * Obtains a hash code for this object.
+ * All instances of this class have the same hash code.
+ * There is only one instance of this class.
+ */
+ @Override
+ public int hashCode() {
+ return PlainSocketFactory.class.hashCode();
+ }
+
+}
diff --git a/src/org/apache/http/conn/scheme/Scheme.java b/src/org/apache/http/conn/scheme/Scheme.java
new file mode 100644
index 0000000..590d59d
--- /dev/null
+++ b/src/org/apache/http/conn/scheme/Scheme.java
@@ -0,0 +1,223 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/Scheme.java $
+ * $Revision: 652950 $
+ * $Date: 2008-05-02 16:49:48 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.conn.scheme;
+
+import java.util.Locale;
+
+import org.apache.http.util.LangUtils;
+
+/**
+ * Encapsulates specifics of a protocol scheme such as "http" or "https".
+ * Schemes are identified by lowercase names.
+ * Supported schemes are typically collected in a
+ * {@link SchemeRegistry SchemeRegistry}.
+ *
+ * <p>
+ * For example, to configure support for "https://" URLs,
+ * you could write code like the following:
+ * </p>
+ * <pre>
+ * Scheme https = new Scheme("https", new MySecureSocketFactory(), 443);
+ * SchemeRegistry.DEFAULT.register(https);
+ * </pre>
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author Michael Becke
+ * @author Jeff Dever
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ */
+public final class Scheme {
+
+ /** The name of this scheme, in lowercase. (e.g. http, https) */
+ private final String name;
+
+ /** The socket factory for this scheme */
+ private final SocketFactory socketFactory;
+
+ /** The default port for this scheme */
+ private final int defaultPort;
+
+ /** Indicates whether this scheme allows for layered connections */
+ private final boolean layered;
+
+
+ /** A string representation, for {@link #toString toString}. */
+ private String stringRep;
+
+
+ /**
+ * Creates a new scheme.
+ * Whether the created scheme allows for layered connections
+ * depends on the class of <code>factory</code>.
+ *
+ * @param name the scheme name, for example "http".
+ * The name will be converted to lowercase.
+ * @param factory the factory for creating sockets for communication
+ * with this scheme
+ * @param port the default port for this scheme
+ */
+ public Scheme(final String name,
+ final SocketFactory factory,
+ final int port) {
+
+ if (name == null) {
+ throw new IllegalArgumentException
+ ("Scheme name may not be null");
+ }
+ if (factory == null) {
+ throw new IllegalArgumentException
+ ("Socket factory may not be null");
+ }
+ if ((port <= 0) || (port > 0xffff)) {
+ throw new IllegalArgumentException
+ ("Port is invalid: " + port);
+ }
+
+ this.name = name.toLowerCase(Locale.ENGLISH);
+ this.socketFactory = factory;
+ this.defaultPort = port;
+ this.layered = (factory instanceof LayeredSocketFactory);
+ }
+
+
+ /**
+ * Obtains the default port.
+ *
+ * @return the default port for this scheme
+ */
+ public final int getDefaultPort() {
+ return defaultPort;
+ }
+
+
+ /**
+ * Obtains the socket factory.
+ * If this scheme is {@link #isLayered layered}, the factory implements
+ * {@link LayeredSocketFactory LayeredSocketFactory}.
+ *
+ * @return the socket factory for this scheme
+ */
+ public final SocketFactory getSocketFactory() {
+ return socketFactory;
+ }
+
+
+ /**
+ * Obtains the scheme name.
+ *
+ * @return the name of this scheme, in lowercase
+ */
+ public final String getName() {
+ return name;
+ }
+
+
+ /**
+ * Indicates whether this scheme allows for layered connections.
+ *
+ * @return <code>true</code> if layered connections are possible,
+ * <code>false</code> otherwise
+ */
+ public final boolean isLayered() {
+ return layered;
+ }
+
+
+ /**
+ * Resolves the correct port for this scheme.
+ * Returns the given port if it is valid, the default port otherwise.
+ *
+ * @param port the port to be resolved,
+ * a negative number to obtain the default port
+ *
+ * @return the given port or the defaultPort
+ */
+ public final int resolvePort(int port) {
+ return ((port <= 0) || (port > 0xffff)) ? defaultPort : port;
+ }
+
+
+ /**
+ * Return a string representation of this object.
+ *
+ * @return a human-readable string description of this scheme
+ */
+ @Override
+ public final String toString() {
+ if (stringRep == null) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(this.name);
+ buffer.append(':');
+ buffer.append(Integer.toString(this.defaultPort));
+ stringRep = buffer.toString();
+ }
+ return stringRep;
+ }
+
+
+ /**
+ * Compares this scheme to an object.
+ *
+ * @param obj the object to compare with
+ *
+ * @return <code>true</code> iff the argument is equal to this scheme
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (this == obj) return true;
+ if (!(obj instanceof Scheme)) return false;
+
+ Scheme s = (Scheme) obj;
+ return (name.equals(s.name) &&
+ defaultPort == s.defaultPort &&
+ layered == s.layered &&
+ socketFactory.equals(s.socketFactory)
+ );
+ } // equals
+
+
+ /**
+ * Obtains a hash code for this scheme.
+ *
+ * @return the hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.defaultPort);
+ hash = LangUtils.hashCode(hash, this.name);
+ hash = LangUtils.hashCode(hash, this.layered);
+ hash = LangUtils.hashCode(hash, this.socketFactory);
+ return hash;
+ }
+
+} // class Scheme
diff --git a/src/org/apache/http/conn/scheme/SchemeRegistry.java b/src/org/apache/http/conn/scheme/SchemeRegistry.java
new file mode 100644
index 0000000..2ee8685
--- /dev/null
+++ b/src/org/apache/http/conn/scheme/SchemeRegistry.java
@@ -0,0 +1,187 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/SchemeRegistry.java $
+ * $Revision: 648356 $
+ * $Date: 2008-04-15 10:57:53 -0700 (Tue, 15 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.conn.scheme;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.HttpHost;
+
+/**
+ * A set of supported protocol {@link Scheme schemes}.
+ * Schemes are identified by lowercase names.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 648356 $ $Date: 2008-04-15 10:57:53 -0700 (Tue, 15 Apr 2008) $
+ *
+ * @since 4.0
+ */
+public final class SchemeRegistry {
+
+ /** The available schemes in this registry. */
+ private final Map<String,Scheme> registeredSchemes;
+
+
+ /**
+ * Creates a new, empty scheme registry.
+ */
+ public SchemeRegistry() {
+ super();
+ registeredSchemes = new LinkedHashMap<String,Scheme>();
+ }
+
+
+ /**
+ * Obtains a scheme by name.
+ *
+ * @param name the name of the scheme to look up (in lowercase)
+ *
+ * @return the scheme, never <code>null</code>
+ *
+ * @throws IllegalStateException
+ * if the scheme with the given name is not registered
+ */
+ public synchronized final Scheme getScheme(String name) {
+ Scheme found = get(name);
+ if (found == null) {
+ throw new IllegalStateException
+ ("Scheme '"+name+"' not registered.");
+ }
+ return found;
+ }
+
+
+ /**
+ * Obtains the scheme for a host.
+ * Convenience method for <code>getScheme(host.getSchemeName())</pre>
+ *
+ * @param host the host for which to obtain the scheme
+ *
+ * @return the scheme for the given host, never <code>null</code>
+ *
+ * @throws IllegalStateException
+ * if a scheme with the respective name is not registered
+ */
+ public synchronized final Scheme getScheme(HttpHost host) {
+ if (host == null) {
+ throw new IllegalArgumentException("Host must not be null.");
+ }
+ return getScheme(host.getSchemeName());
+ }
+
+
+ /**
+ * Obtains a scheme by name, if registered.
+ *
+ * @param name the name of the scheme to look up (in lowercase)
+ *
+ * @return the scheme, or
+ * <code>null</code> if there is none by this name
+ */
+ public synchronized final Scheme get(String name) {
+ if (name == null)
+ throw new IllegalArgumentException("Name must not be null.");
+
+ // leave it to the caller to use the correct name - all lowercase
+ //name = name.toLowerCase();
+ Scheme found = registeredSchemes.get(name);
+ return found;
+ }
+
+
+ /**
+ * Registers a scheme.
+ * The scheme can later be retrieved by its name
+ * using {@link #getScheme(String) getScheme} or {@link #get get}.
+ *
+ * @param sch the scheme to register
+ *
+ * @return the scheme previously registered with that name, or
+ * <code>null</code> if none was registered
+ */
+ public synchronized final Scheme register(Scheme sch) {
+ if (sch == null)
+ throw new IllegalArgumentException("Scheme must not be null.");
+
+ Scheme old = registeredSchemes.put(sch.getName(), sch);
+ return old;
+ }
+
+
+ /**
+ * Unregisters a scheme.
+ *
+ * @param name the name of the scheme to unregister (in lowercase)
+ *
+ * @return the unregistered scheme, or
+ * <code>null</code> if there was none
+ */
+ public synchronized final Scheme unregister(String name) {
+ if (name == null)
+ throw new IllegalArgumentException("Name must not be null.");
+
+ // leave it to the caller to use the correct name - all lowercase
+ //name = name.toLowerCase();
+ Scheme gone = registeredSchemes.remove(name);
+ return gone;
+ }
+
+
+ /**
+ * Obtains the names of the registered schemes in their default order.
+ *
+ * @return List containing registered scheme names.
+ */
+ public synchronized final List<String> getSchemeNames() {
+ return new ArrayList<String>(registeredSchemes.keySet());
+ }
+
+ /**
+ * Populates the internal collection of registered {@link Scheme protocol schemes}
+ * with the content of the map passed as a parameter.
+ *
+ * @param map protocol schemes
+ */
+ public synchronized void setItems(final Map<String, Scheme> map) {
+ if (map == null) {
+ return;
+ }
+ registeredSchemes.clear();
+ registeredSchemes.putAll(map);
+ }
+
+} // class SchemeRegistry
+
diff --git a/src/org/apache/http/conn/scheme/SocketFactory.java b/src/org/apache/http/conn/scheme/SocketFactory.java
new file mode 100644
index 0000000..bb553b2
--- /dev/null
+++ b/src/org/apache/http/conn/scheme/SocketFactory.java
@@ -0,0 +1,138 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/SocketFactory.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.params.HttpParams;
+
+/**
+ * A factory for creating and connecting sockets.
+ * The factory encapsulates the logic for establishing a socket connection.
+ * <br/>
+ * Both {@link java.lang.Object#equals(java.lang.Object) Object.equals()}
+ * and {@link java.lang.Object#hashCode() Object.hashCode()}
+ * must be overridden for the correct operation of some connection managers.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ */
+public interface SocketFactory {
+
+ /**
+ * Creates a new, unconnected socket.
+ * The socket should subsequently be passed to
+ * {@link #connectSocket connectSocket}.
+ *
+ * @return a new socket
+ *
+ * @throws IOException if an I/O error occurs while creating the socket
+ */
+ Socket createSocket()
+ throws IOException
+ ;
+
+
+ /**
+ * Connects a socket to the given host.
+ *
+ * @param sock the socket to connect, as obtained from
+ * {@link #createSocket createSocket}.
+ * <code>null</code> indicates that a new socket
+ * should be created and connected.
+ * @param host the host to connect to
+ * @param port the port to connect to on the host
+ * @param localAddress the local address to bind the socket to, or
+ * <code>null</code> for any
+ * @param localPort the port on the local machine,
+ * 0 or a negative number for any
+ * @param params additional {@link HttpParams parameters} for connecting
+ *
+ * @return the connected socket. The returned object may be different
+ * from the <code>sock</code> argument if this factory supports
+ * a layered protocol.
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnknownHostException if the IP address of the target host
+ * can not be determined
+ * @throws ConnectTimeoutException if the socket cannot be connected
+ * within the time limit defined in the <code>params</code>
+ */
+ Socket connectSocket(
+ Socket sock,
+ String host,
+ int port,
+ InetAddress localAddress,
+ int localPort,
+ HttpParams params
+ ) throws IOException, UnknownHostException, ConnectTimeoutException;
+
+
+ /**
+ * Checks whether a socket provides a secure connection.
+ * The socket must be {@link #connectSocket connected}
+ * by this factory.
+ * The factory will <i>not</i> perform I/O operations
+ * in this method.
+ * <br/>
+ * As a rule of thumb, plain sockets are not secure and
+ * TLS/SSL sockets are secure. However, there may be
+ * application specific deviations. For example, a plain
+ * socket to a host in the same intranet ("trusted zone")
+ * could be considered secure. On the other hand, a
+ * TLS/SSL socket could be considered insecure based on
+ * the cypher suite chosen for the connection.
+ *
+ * @param sock the connected socket to check
+ *
+ * @return <code>true</code> if the connection of the socket
+ * should be considered secure, or
+ * <code>false</code> if it should not
+ *
+ * @throws IllegalArgumentException
+ * if the argument is invalid, for example because it is
+ * not a connected socket or was created by a different
+ * socket factory.
+ * Note that socket factories are <i>not</i> required to
+ * check these conditions, they may simply return a default
+ * value when called with an invalid socket argument.
+ */
+ boolean isSecure(Socket sock)
+ throws IllegalArgumentException
+ ;
+
+}
diff --git a/src/org/apache/http/conn/ssl/AbstractVerifier.java b/src/org/apache/http/conn/ssl/AbstractVerifier.java
new file mode 100644
index 0000000..5195e58
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/AbstractVerifier.java
@@ -0,0 +1,343 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import org.apache.http.conn.util.InetAddressUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * Abstract base class for all standard {@link X509HostnameVerifier}
+ * implementations.
+ *
+ * @author Julius Davies
+ */
+public abstract class AbstractVerifier implements X509HostnameVerifier {
+
+ /**
+ * This contains a list of 2nd-level domains that aren't allowed to
+ * have wildcards when combined with country-codes.
+ * For example: [*.co.uk].
+ * <p/>
+ * The [*.co.uk] problem is an interesting one. Should we just hope
+ * that CA's would never foolishly allow such a certificate to happen?
+ * Looks like we're the only implementation guarding against this.
+ * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
+ */
+ private final static String[] BAD_COUNTRY_2LDS =
+ { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+ "lg", "ne", "net", "or", "org" };
+
+ static {
+ // Just in case developer forgot to manually sort the array. :-)
+ Arrays.sort(BAD_COUNTRY_2LDS);
+ }
+
+ public AbstractVerifier() {
+ super();
+ }
+
+ public final void verify(String host, SSLSocket ssl)
+ throws IOException {
+ if(host == null) {
+ throw new NullPointerException("host to verify is null");
+ }
+
+ ssl.startHandshake();
+ SSLSession session = ssl.getSession();
+ if(session == null) {
+ // In our experience this only happens under IBM 1.4.x when
+ // spurious (unrelated) certificates show up in the server'
+ // chain. Hopefully this will unearth the real problem:
+ InputStream in = ssl.getInputStream();
+ in.available();
+ /*
+ If you're looking at the 2 lines of code above because
+ you're running into a problem, you probably have two
+ options:
+
+ #1. Clean up the certificate chain that your server
+ is presenting (e.g. edit "/etc/apache2/server.crt"
+ or wherever it is your server's certificate chain
+ is defined).
+
+ OR
+
+ #2. Upgrade to an IBM 1.5.x or greater JVM, or switch
+ to a non-IBM JVM.
+ */
+
+ // If ssl.getInputStream().available() didn't cause an
+ // exception, maybe at least now the session is available?
+ session = ssl.getSession();
+ if(session == null) {
+ // If it's still null, probably a startHandshake() will
+ // unearth the real problem.
+ ssl.startHandshake();
+
+ // Okay, if we still haven't managed to cause an exception,
+ // might as well go for the NPE. Or maybe we're okay now?
+ session = ssl.getSession();
+ }
+ }
+
+ Certificate[] certs = session.getPeerCertificates();
+ X509Certificate x509 = (X509Certificate) certs[0];
+ verify(host, x509);
+ }
+
+ public final boolean verify(String host, SSLSession session) {
+ try {
+ Certificate[] certs = session.getPeerCertificates();
+ X509Certificate x509 = (X509Certificate) certs[0];
+ verify(host, x509);
+ return true;
+ }
+ catch(SSLException e) {
+ return false;
+ }
+ }
+
+ public final void verify(String host, X509Certificate cert)
+ throws SSLException {
+ String[] cns = getCNs(cert);
+ String[] subjectAlts = getDNSSubjectAlts(cert);
+ verify(host, cns, subjectAlts);
+ }
+
+ public final void verify(final String host, final String[] cns,
+ final String[] subjectAlts,
+ final boolean strictWithSubDomains)
+ throws SSLException {
+
+ // Build the list of names we're going to check. Our DEFAULT and
+ // STRICT implementations of the HostnameVerifier only use the
+ // first CN provided. All other CNs are ignored.
+ // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
+ LinkedList<String> names = new LinkedList<String>();
+ if(cns != null && cns.length > 0 && cns[0] != null) {
+ names.add(cns[0]);
+ }
+ if(subjectAlts != null) {
+ for (String subjectAlt : subjectAlts) {
+ if (subjectAlt != null) {
+ names.add(subjectAlt);
+ }
+ }
+ }
+
+ if(names.isEmpty()) {
+ String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
+ throw new SSLException(msg);
+ }
+
+ // StringBuffer for building the error message.
+ StringBuffer buf = new StringBuffer();
+
+ // We're can be case-insensitive when comparing the host we used to
+ // establish the socket to the hostname in the certificate.
+ String hostName = host.trim().toLowerCase(Locale.ENGLISH);
+ boolean match = false;
+ for(Iterator<String> it = names.iterator(); it.hasNext();) {
+ // Don't trim the CN, though!
+ String cn = it.next();
+ cn = cn.toLowerCase(Locale.ENGLISH);
+ // Store CN in StringBuffer in case we need to report an error.
+ buf.append(" <");
+ buf.append(cn);
+ buf.append('>');
+ if(it.hasNext()) {
+ buf.append(" OR");
+ }
+
+ // The CN better have at least two dots if it wants wildcard
+ // action. It also can't be [*.co.uk] or [*.co.jp] or
+ // [*.org.uk], etc...
+ boolean doWildcard = cn.startsWith("*.") &&
+ cn.lastIndexOf('.') >= 0 &&
+ acceptableCountryWildcard(cn) &&
+ !InetAddressUtils.isIPv4Address(host);
+
+ if(doWildcard) {
+ match = hostName.endsWith(cn.substring(1));
+ if(match && strictWithSubDomains) {
+ // If we're in strict mode, then [*.foo.com] is not
+ // allowed to match [a.b.foo.com]
+ match = countDots(hostName) == countDots(cn);
+ }
+ } else {
+ match = hostName.equals(cn);
+ }
+ if(match) {
+ break;
+ }
+ }
+ if(!match) {
+ throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
+ }
+ }
+
+ public static boolean acceptableCountryWildcard(String cn) {
+ int cnLen = cn.length();
+ if(cnLen >= 7 && cnLen <= 9) {
+ // Look for the '.' in the 3rd-last position:
+ if(cn.charAt(cnLen - 3) == '.') {
+ // Trim off the [*.] and the [.XX].
+ String s = cn.substring(2, cnLen - 3);
+ // And test against the sorted array of bad 2lds:
+ int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
+ return x < 0;
+ }
+ }
+ return true;
+ }
+
+ public static String[] getCNs(X509Certificate cert) {
+ LinkedList<String> cnList = new LinkedList<String>();
+ /*
+ Sebastian Hauer's original StrictSSLProtocolSocketFactory used
+ getName() and had the following comment:
+
+ Parses a X.500 distinguished name for the value of the
+ "Common Name" field. This is done a bit sloppy right
+ now and should probably be done a bit more according to
+ <code>RFC 2253</code>.
+
+ I've noticed that toString() seems to do a better job than
+ getName() on these X500Principal objects, so I'm hoping that
+ addresses Sebastian's concern.
+
+ For example, getName() gives me this:
+ 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d
+
+ whereas toString() gives me this:
+ EMAILADDRESS=juliusdavies@cucbc.com
+
+ Looks like toString() even works with non-ascii domain names!
+ I tested it with "&#x82b1;&#x5b50;.co.jp" and it worked fine.
+ */
+ String subjectPrincipal = cert.getSubjectX500Principal().toString();
+ StringTokenizer st = new StringTokenizer(subjectPrincipal, ",");
+ while(st.hasMoreTokens()) {
+ String tok = st.nextToken();
+ int x = tok.indexOf("CN=");
+ if(x >= 0) {
+ cnList.add(tok.substring(x + 3));
+ }
+ }
+ if(!cnList.isEmpty()) {
+ String[] cns = new String[cnList.size()];
+ cnList.toArray(cns);
+ return cns;
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Extracts the array of SubjectAlt DNS names from an X509Certificate.
+ * Returns null if there aren't any.
+ * <p/>
+ * Note: Java doesn't appear able to extract international characters
+ * from the SubjectAlts. It can only extract international characters
+ * from the CN field.
+ * <p/>
+ * (Or maybe the version of OpenSSL I'm using to test isn't storing the
+ * international characters correctly in the SubjectAlts?).
+ *
+ * @param cert X509Certificate
+ * @return Array of SubjectALT DNS names stored in the certificate.
+ */
+ public static String[] getDNSSubjectAlts(X509Certificate cert) {
+ LinkedList<String> subjectAltList = new LinkedList<String>();
+ Collection<List<?>> c = null;
+ try {
+ c = cert.getSubjectAlternativeNames();
+ }
+ catch(CertificateParsingException cpe) {
+ Logger.getLogger(AbstractVerifier.class.getName())
+ .log(Level.FINE, "Error parsing certificate.", cpe);
+ }
+ if(c != null) {
+ for (List<?> aC : c) {
+ List<?> list = aC;
+ int type = ((Integer) list.get(0)).intValue();
+ // If type is 2, then we've got a dNSName
+ if (type == 2) {
+ String s = (String) list.get(1);
+ subjectAltList.add(s);
+ }
+ }
+ }
+ if(!subjectAltList.isEmpty()) {
+ String[] subjectAlts = new String[subjectAltList.size()];
+ subjectAltList.toArray(subjectAlts);
+ return subjectAlts;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Counts the number of dots "." in a string.
+ * @param s string to count dots from
+ * @return number of dots
+ */
+ public static int countDots(final String s) {
+ int count = 0;
+ for(int i = 0; i < s.length(); i++) {
+ if(s.charAt(i) == '.') {
+ count++;
+ }
+ }
+ return count;
+ }
+
+}
diff --git a/src/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java b/src/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
new file mode 100644
index 0000000..05828fb
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
@@ -0,0 +1,54 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+/**
+ * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+ * off. This implementation is a no-op, and never throws the SSLException.
+ *
+ * @author Julius Davies
+ */
+public class AllowAllHostnameVerifier extends AbstractVerifier {
+
+ public final void verify(
+ final String host,
+ final String[] cns,
+ final String[] subjectAlts) {
+ // Allow everything - so never blowup.
+ }
+
+ @Override
+ public final String toString() {
+ return "ALLOW_ALL";
+ }
+
+}
diff --git a/src/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java b/src/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
new file mode 100644
index 0000000..f4129d6
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
@@ -0,0 +1,62 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * The HostnameVerifier that works the same way as Curl and Firefox.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts.
+ * <p/>
+ * The only difference between BROWSER_COMPATIBLE and STRICT is that a wildcard
+ * (such as "*.foo.com") with BROWSER_COMPATIBLE matches all subdomains,
+ * including "a.b.foo.com".
+ *
+ * @author Julius Davies
+ */
+public class BrowserCompatHostnameVerifier extends AbstractVerifier {
+
+ public final void verify(
+ final String host,
+ final String[] cns,
+ final String[] subjectAlts) throws SSLException {
+ verify(host, cns, subjectAlts, false);
+ }
+
+ @Override
+ public final String toString() {
+ return "BROWSER_COMPATIBLE";
+ }
+
+}
diff --git a/src/org/apache/http/conn/ssl/SSLSocketFactory.java b/src/org/apache/http/conn/ssl/SSLSocketFactory.java
new file mode 100644
index 0000000..498b43e
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -0,0 +1,384 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java $
+ * $Revision: 659194 $
+ * $Date: 2008-05-22 11:33:47 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import org.apache.http.conn.scheme.HostNameResolver;
+import org.apache.http.conn.scheme.LayeredSocketFactory;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * Layered socket factory for TLS/SSL connections, based on JSSE.
+ *.
+ * <p>
+ * SSLSocketFactory can be used to validate the identity of the HTTPS
+ * server against a list of trusted certificates and to authenticate to
+ * the HTTPS server using a private key.
+ * </p>
+ *
+ * <p>
+ * SSLSocketFactory will enable server authentication when supplied with
+ * a {@link KeyStore truststore} file containg one or several trusted
+ * certificates. The client secure socket will reject the connection during
+ * the SSL session handshake if the target HTTPS server attempts to
+ * authenticate itself with a non-trusted certificate.
+ * </p>
+ *
+ * <p>
+ * Use JDK keytool utility to import a trusted certificate and generate a truststore file:
+ * <pre>
+ * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ * </pre>
+ * </p>
+ *
+ * <p>
+ * SSLSocketFactory will enable client authentication when supplied with
+ * a {@link KeyStore keystore} file containg a private key/public certificate
+ * pair. The client secure socket will use the private key to authenticate
+ * itself to the target HTTPS server during the SSL session handshake if
+ * requested to do so by the server.
+ * The target HTTPS server will in its turn verify the certificate presented
+ * by the client in order to establish client's authenticity
+ * </p>
+ *
+ * <p>
+ * Use the following sequence of actions to generate a keystore file
+ * </p>
+ * <ul>
+ * <li>
+ * <p>
+ * Use JDK keytool utility to generate a new key
+ * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ * For simplicity use the same password for the key as that of the keystore
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Issue a certificate signing request (CSR)
+ * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Send the certificate request to the trusted Certificate Authority for signature.
+ * One may choose to act as her own CA and sign the certificate request using a PKI
+ * tool, such as OpenSSL.
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Import the trusted CA root certificate
+ * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Import the PKCS#7 file containg the complete certificate chain
+ * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Verify the content the resultant keystore file
+ * <pre>keytool -list -v -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * </ul>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author Julius Davies
+ */
+
+public class SSLSocketFactory implements LayeredSocketFactory {
+
+ public static final String TLS = "TLS";
+ public static final String SSL = "SSL";
+ public static final String SSLV2 = "SSLv2";
+
+ public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
+ = new AllowAllHostnameVerifier();
+
+ public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
+ = new BrowserCompatHostnameVerifier();
+
+ public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
+ = new StrictHostnameVerifier();
+ /**
+ * The factory using the default JVM settings for secure connections.
+ */
+ private static final SSLSocketFactory DEFAULT_FACTORY = new SSLSocketFactory();
+
+ /**
+ * Gets an singleton instance of the SSLProtocolSocketFactory.
+ * @return a SSLProtocolSocketFactory
+ */
+ public static SSLSocketFactory getSocketFactory() {
+ return DEFAULT_FACTORY;
+ }
+
+ private final SSLContext sslcontext;
+ private final javax.net.ssl.SSLSocketFactory socketfactory;
+ private final HostNameResolver nameResolver;
+ private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+
+ public SSLSocketFactory(
+ String algorithm,
+ final KeyStore keystore,
+ final String keystorePassword,
+ final KeyStore truststore,
+ final SecureRandom random,
+ final HostNameResolver nameResolver)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ super();
+ if (algorithm == null) {
+ algorithm = TLS;
+ }
+ KeyManager[] keymanagers = null;
+ if (keystore != null) {
+ keymanagers = createKeyManagers(keystore, keystorePassword);
+ }
+ TrustManager[] trustmanagers = null;
+ if (truststore != null) {
+ trustmanagers = createTrustManagers(truststore);
+ }
+ this.sslcontext = SSLContext.getInstance(algorithm);
+ this.sslcontext.init(keymanagers, trustmanagers, random);
+ this.socketfactory = this.sslcontext.getSocketFactory();
+ this.nameResolver = nameResolver;
+ }
+
+ public SSLSocketFactory(
+ final KeyStore keystore,
+ final String keystorePassword,
+ final KeyStore truststore)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ this(TLS, keystore, keystorePassword, truststore, null, null);
+ }
+
+ public SSLSocketFactory(final KeyStore keystore, final String keystorePassword)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ this(TLS, keystore, keystorePassword, null, null, null);
+ }
+
+ public SSLSocketFactory(final KeyStore truststore)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ this(TLS, null, null, truststore, null, null);
+ }
+
+ /**
+ * Creates the default SSL socket factory.
+ * This constructor is used exclusively to instantiate the factory for
+ * {@link #getSocketFactory getSocketFactory}.
+ */
+ private SSLSocketFactory() {
+ super();
+ this.sslcontext = null;
+ this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+ this.nameResolver = null;
+ }
+
+ private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password)
+ throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+ if (keystore == null) {
+ throw new IllegalArgumentException("Keystore may not be null");
+ }
+ KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+ kmfactory.init(keystore, password != null ? password.toCharArray(): null);
+ return kmfactory.getKeyManagers();
+ }
+
+ private static TrustManager[] createTrustManagers(final KeyStore keystore)
+ throws KeyStoreException, NoSuchAlgorithmException {
+ if (keystore == null) {
+ throw new IllegalArgumentException("Keystore may not be null");
+ }
+ TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmfactory.init(keystore);
+ return tmfactory.getTrustManagers();
+ }
+
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket createSocket()
+ throws IOException {
+
+ // the cast makes sure that the factory is working as expected
+ return (SSLSocket) this.socketfactory.createSocket();
+ }
+
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket connectSocket(
+ final Socket sock,
+ final String host,
+ final int port,
+ final InetAddress localAddress,
+ int localPort,
+ final HttpParams params
+ ) throws IOException {
+
+ if (host == null) {
+ throw new IllegalArgumentException("Target host may not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters may not be null.");
+ }
+
+ SSLSocket sslsock = (SSLSocket)
+ ((sock != null) ? sock : createSocket());
+
+ if ((localAddress != null) || (localPort > 0)) {
+
+ // we need to bind explicitly
+ if (localPort < 0)
+ localPort = 0; // indicates "any"
+
+ InetSocketAddress isa =
+ new InetSocketAddress(localAddress, localPort);
+ sslsock.bind(isa);
+ }
+
+ int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
+ int soTimeout = HttpConnectionParams.getSoTimeout(params);
+
+ InetSocketAddress remoteAddress;
+ if (this.nameResolver != null) {
+ remoteAddress = new InetSocketAddress(this.nameResolver.resolve(host), port);
+ } else {
+ remoteAddress = new InetSocketAddress(host, port);
+ }
+
+ sslsock.connect(remoteAddress, connTimeout);
+
+ sslsock.setSoTimeout(soTimeout);
+ try {
+ hostnameVerifier.verify(host, sslsock);
+ // verifyHostName() didn't blowup - good!
+ } catch (IOException iox) {
+ // close the socket before re-throwing the exception
+ try { sslsock.close(); } catch (Exception x) { /*ignore*/ }
+ throw iox;
+ }
+
+ return sslsock;
+ }
+
+
+ /**
+ * Checks whether a socket connection is secure.
+ * This factory creates TLS/SSL socket connections
+ * which, by default, are considered secure.
+ * <br/>
+ * Derived classes may override this method to perform
+ * runtime checks, for example based on the cypher suite.
+ *
+ * @param sock the connected socket
+ *
+ * @return <code>true</code>
+ *
+ * @throws IllegalArgumentException if the argument is invalid
+ */
+ public boolean isSecure(Socket sock)
+ throws IllegalArgumentException {
+
+ if (sock == null) {
+ throw new IllegalArgumentException("Socket may not be null.");
+ }
+ // This instanceof check is in line with createSocket() above.
+ if (!(sock instanceof SSLSocket)) {
+ throw new IllegalArgumentException
+ ("Socket not created by this factory.");
+ }
+ // This check is performed last since it calls the argument object.
+ if (sock.isClosed()) {
+ throw new IllegalArgumentException("Socket is closed.");
+ }
+
+ return true;
+
+ } // isSecure
+
+
+ // non-javadoc, see interface LayeredSocketFactory
+ public Socket createSocket(
+ final Socket socket,
+ final String host,
+ final int port,
+ final boolean autoClose
+ ) throws IOException, UnknownHostException {
+ SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
+ socket,
+ host,
+ port,
+ autoClose
+ );
+ hostnameVerifier.verify(host, sslSocket);
+ // verifyHostName() didn't blowup - good!
+ return sslSocket;
+ }
+
+ public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) {
+ if ( hostnameVerifier == null ) {
+ throw new IllegalArgumentException("Hostname verifier may not be null");
+ }
+ this.hostnameVerifier = hostnameVerifier;
+ }
+
+ public X509HostnameVerifier getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+
+}
diff --git a/src/org/apache/http/conn/ssl/StrictHostnameVerifier.java b/src/org/apache/http/conn/ssl/StrictHostnameVerifier.java
new file mode 100644
index 0000000..5eb0d96
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/StrictHostnameVerifier.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * The Strict HostnameVerifier works the same way as Sun Java 1.4, Sun
+ * Java 5, Sun Java 6-rc. It's also pretty close to IE6. This
+ * implementation appears to be compliant with RFC 2818 for dealing with
+ * wildcards.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts. The
+ * one divergence from IE6 is how we only check the first CN. IE6 allows
+ * a match against any of the CNs present. We decided to follow in
+ * Sun Java 1.4's footsteps and only check the first CN. (If you need
+ * to check all the CN's, feel free to write your own implementation!).
+ * <p/>
+ * A wildcard such as "*.foo.com" matches only subdomains in the same
+ * level, for example "a.foo.com". It does not match deeper subdomains
+ * such as "a.b.foo.com".
+ *
+ * @author Julius Davies
+ */
+public class StrictHostnameVerifier extends AbstractVerifier {
+
+ public final void verify(
+ final String host,
+ final String[] cns,
+ final String[] subjectAlts) throws SSLException {
+ verify(host, cns, subjectAlts, true);
+ }
+
+ @Override
+ public final String toString() {
+ return "STRICT";
+ }
+
+}
diff --git a/src/org/apache/http/conn/ssl/X509HostnameVerifier.java b/src/org/apache/http/conn/ssl/X509HostnameVerifier.java
new file mode 100644
index 0000000..05ad04d
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/X509HostnameVerifier.java
@@ -0,0 +1,86 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java $
+ * $Revision: 618365 $
+ * $Date: 2008-02-04 10:20:08 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Interface for checking if a hostname matches the names stored inside the
+ * server's X.509 certificate. Implements javax.net.ssl.HostnameVerifier, but
+ * we don't actually use that interface. Instead we added some methods that
+ * take String parameters (instead of javax.net.ssl.HostnameVerifier's
+ * SSLSession). JUnit is a lot easier this way! :-)
+ * <p/>
+ * We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
+ * HostnameVerifier.ALLOW_ALL implementations. But feel free to define
+ * your own implementation!
+ * <p/>
+ * Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
+ * HttpClient "contrib" repository.
+ *
+ * @author Julius Davies
+ * @author <a href="mailto:hauer@psicode.com">Sebastian Hauer</a>
+ *
+ * @since 4.0 (8-Dec-2006)
+ */
+public interface X509HostnameVerifier extends HostnameVerifier {
+
+ boolean verify(String host, SSLSession session);
+
+ void verify(String host, SSLSocket ssl) throws IOException;
+
+ void verify(String host, X509Certificate cert) throws SSLException;
+
+ /**
+ * Checks to see if the supplied hostname matches any of the supplied CNs
+ * or "DNS" Subject-Alts. Most implementations only look at the first CN,
+ * and ignore any additional CNs. Most implementations do look at all of
+ * the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
+ * according to RFC 2818.
+ *
+ * @param cns CN fields, in order, as extracted from the X.509
+ * certificate.
+ * @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
+ * from the X.509 certificate.
+ * @param host The hostname to verify.
+ * @throws SSLException If verification failed.
+ */
+ void verify(String host, String[] cns, String[] subjectAlts)
+ throws SSLException;
+
+
+}
diff --git a/src/org/apache/http/conn/ssl/package.html b/src/org/apache/http/conn/ssl/package.html
new file mode 100644
index 0000000..a5c737f
--- /dev/null
+++ b/src/org/apache/http/conn/ssl/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+TLS/SSL specific parts of the <i>HttpConn</i> API.
+
+</body>
+</html>
diff --git a/src/org/apache/http/conn/util/InetAddressUtils.java b/src/org/apache/http/conn/util/InetAddressUtils.java
new file mode 100644
index 0000000..71f2190
--- /dev/null
+++ b/src/org/apache/http/conn/util/InetAddressUtils.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/util/InetAddressUtils.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.util;
+
+import java.util.regex.Pattern;
+
+/**
+ * A collection of utilities relating to InetAddresses.
+ */
+public class InetAddressUtils {
+
+ private InetAddressUtils() {
+ }
+
+ private static final Pattern IPV4_PATTERN =
+ Pattern.compile(
+ "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
+
+ private static final Pattern IPV6_STD_PATTERN =
+ Pattern.compile(
+ "^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
+
+ private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
+ Pattern.compile(
+ "^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
+
+ public static boolean isIPv4Address(final String input) {
+ return IPV4_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv6StdAddress(final String input) {
+ return IPV6_STD_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv6HexCompressedAddress(final String input) {
+ return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv6Address(final String input) {
+ return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
+ }
+
+}
diff --git a/src/org/apache/http/cookie/ClientCookie.java b/src/org/apache/http/cookie/ClientCookie.java
new file mode 100644
index 0000000..96edec9
--- /dev/null
+++ b/src/org/apache/http/cookie/ClientCookie.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/ClientCookie.java $
+ * $Revision: 578403 $
+ * $Date: 2007-09-22 03:56:04 -0700 (Sat, 22 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+/**
+ * ClientCookie extends the standard {@link Cookie} interface with
+ * additional client specific functionality such ability to retrieve
+ * original cookie attributes exactly as they were specified by the
+ * origin server. This is important for generating the <tt>Cookie</tt>
+ * header because some cookie specifications require that the
+ * <tt>Cookie</tt> header should include certain attributes only if
+ * they were specified in the <tt>Set-Cookie</tt> header.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface ClientCookie extends Cookie {
+
+ // RFC2109 attributes
+ public static final String VERSION_ATTR = "version";
+ public static final String PATH_ATTR = "path";
+ public static final String DOMAIN_ATTR = "domain";
+ public static final String MAX_AGE_ATTR = "max-age";
+ public static final String SECURE_ATTR = "secure";
+ public static final String COMMENT_ATTR = "comment";
+ public static final String EXPIRES_ATTR = "expires";
+
+ // RFC2965 attributes
+ public static final String PORT_ATTR = "port";
+ public static final String COMMENTURL_ATTR = "commenturl";
+ public static final String DISCARD_ATTR = "discard";
+
+ String getAttribute(String name);
+
+ boolean containsAttribute(String name);
+
+} \ No newline at end of file
diff --git a/src/org/apache/http/cookie/Cookie.java b/src/org/apache/http/cookie/Cookie.java
new file mode 100644
index 0000000..5eae9d5
--- /dev/null
+++ b/src/org/apache/http/cookie/Cookie.java
@@ -0,0 +1,139 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/Cookie.java $
+ * $Revision: 578403 $
+ * $Date: 2007-09-22 03:56:04 -0700 (Sat, 22 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.util.Date;
+
+/**
+ * HTTP "magic-cookie" represents a piece of state information
+ * that the HTTP agent and the target server can exchange to maintain
+ * a session.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface Cookie {
+
+ /**
+ * Returns the name.
+ *
+ * @return String name The name
+ */
+ String getName();
+
+ /**
+ * Returns the value.
+ *
+ * @return String value The current value.
+ */
+ String getValue();
+
+ /**
+ * Returns the comment describing the purpose of this cookie, or
+ * <tt>null</tt> if no such comment has been defined.
+ *
+ * @return comment
+ */
+ String getComment();
+
+ /**
+ * If a user agent (web browser) presents this cookie to a user, the
+ * cookie's purpose will be described by the information at this URL.
+ */
+ String getCommentURL();
+
+ /**
+ * Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
+ * if none exists.
+ * <p><strong>Note:</strong> the object returned by this method is
+ * considered immutable. Changing it (e.g. using setTime()) could result
+ * in undefined behaviour. Do so at your peril. </p>
+ * @return Expiration {@link Date}, or <tt>null</tt>.
+ */
+ Date getExpiryDate();
+
+ /**
+ * Returns <tt>false</tt> if the cookie should be discarded at the end
+ * of the "session"; <tt>true</tt> otherwise.
+ *
+ * @return <tt>false</tt> if the cookie should be discarded at the end
+ * of the "session"; <tt>true</tt> otherwise
+ */
+ boolean isPersistent();
+
+ /**
+ * Returns domain attribute of the cookie.
+ *
+ * @return the value of the domain attribute
+ */
+ String getDomain();
+
+ /**
+ * Returns the path attribute of the cookie
+ *
+ * @return The value of the path attribute.
+ */
+ String getPath();
+
+ /**
+ * Get the Port attribute. It restricts the ports to which a cookie
+ * may be returned in a Cookie request header.
+ */
+ int[] getPorts();
+
+ /**
+ * Indicates whether this cookie requires a secure connection.
+ *
+ * @return <code>true</code> if this cookie should only be sent
+ * over secure connections, <code>false</code> otherwise.
+ */
+ boolean isSecure();
+
+ /**
+ * Returns the version of the cookie specification to which this
+ * cookie conforms.
+ *
+ * @return the version of the cookie.
+ */
+ int getVersion();
+
+ /**
+ * Returns true if this cookie has expired.
+ * @param date Current time
+ *
+ * @return <tt>true</tt> if the cookie has expired.
+ */
+ boolean isExpired(final Date date);
+
+}
+
diff --git a/src/org/apache/http/cookie/CookieAttributeHandler.java b/src/org/apache/http/cookie/CookieAttributeHandler.java
new file mode 100644
index 0000000..a79d115
--- /dev/null
+++ b/src/org/apache/http/cookie/CookieAttributeHandler.java
@@ -0,0 +1,78 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java $
+ * $Revision: 558519 $
+ * $Date: 2007-07-22 11:19:49 -0700 (Sun, 22 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.cookie;
+
+/**
+ * Ths interface represents a cookie attribute handler responsible
+ * for parsing, validating, and matching a specific cookie attribute,
+ * such as path, domain, port, etc.
+ *
+ * Different cookie specifications can provide a specific
+ * implementation for this class based on their cookie handling
+ * rules.
+ *
+ * @author jain.samit@gmail.com (Samit Jain)
+ *
+ * @since 4.0
+ */
+public interface CookieAttributeHandler {
+
+ /**
+ * Parse the given cookie attribute value and update the corresponding
+ * {@link org.apache.http.cookie.Cookie} property.
+ *
+ * @param cookie {@link org.apache.http.cookie.Cookie} to be updated
+ * @param value cookie attribute value from the cookie response header
+ */
+ void parse(SetCookie cookie, String value)
+ throws MalformedCookieException;
+
+ /**
+ * Peforms cookie validation for the given attribute value.
+ *
+ * @param cookie {@link org.apache.http.cookie.Cookie} to validate
+ * @param origin the cookie source to validate against
+ * @throws MalformedCookieException if cookie validation fails for this attribute
+ */
+ void validate(Cookie cookie, CookieOrigin origin)
+ throws MalformedCookieException;
+
+ /**
+ * Matches the given value (property of the destination host where request is being
+ * submitted) with the corresponding cookie attribute.
+ *
+ * @param cookie {@link org.apache.http.cookie.Cookie} to match
+ * @param origin the cookie source to match against
+ * @return <tt>true</tt> if the match is successful; <tt>false</tt> otherwise
+ */
+ boolean match(Cookie cookie, CookieOrigin origin);
+
+}
diff --git a/src/org/apache/http/cookie/CookieIdentityComparator.java b/src/org/apache/http/cookie/CookieIdentityComparator.java
new file mode 100644
index 0000000..4fc701c
--- /dev/null
+++ b/src/org/apache/http/cookie/CookieIdentityComparator.java
@@ -0,0 +1,68 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java $
+ * $Revision: 618308 $
+ * $Date: 2008-02-04 07:51:19 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * This cookie comparator can be used to compare identity of cookies.
+ *
+ * <p>
+ * Cookies are considered identical if their names are equal and
+ * their domain attributes match ignoring case.
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class CookieIdentityComparator implements Serializable, Comparator<Cookie> {
+
+ private static final long serialVersionUID = 4466565437490631532L;
+
+ public int compare(final Cookie c1, final Cookie c2) {
+ int res = c1.getName().compareTo(c2.getName());
+ if (res == 0) {
+ // do not differentiate empty and null domains
+ String d1 = c1.getDomain();
+ if (d1 == null) {
+ d1 = "";
+ }
+ String d2 = c2.getDomain();
+ if (d2 == null) {
+ d2 = "";
+ }
+ res = d1.compareToIgnoreCase(d2);
+ }
+ return res;
+ }
+
+}
diff --git a/src/org/apache/http/cookie/CookieOrigin.java b/src/org/apache/http/cookie/CookieOrigin.java
new file mode 100644
index 0000000..ad0448a
--- /dev/null
+++ b/src/org/apache/http/cookie/CookieOrigin.java
@@ -0,0 +1,108 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookieOrigin.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.cookie;
+
+import java.util.Locale;
+
+/**
+ * CookieOrigin class incapsulates details of an origin server that
+ * are relevant when parsing, validating or matching HTTP cookies.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public final class CookieOrigin {
+
+ private final String host;
+ private final int port;
+ private final String path;
+ private final boolean secure;
+
+ public CookieOrigin(final String host, int port, final String path, boolean secure) {
+ super();
+ if (host == null) {
+ throw new IllegalArgumentException(
+ "Host of origin may not be null");
+ }
+ if (host.trim().length() == 0) {
+ throw new IllegalArgumentException(
+ "Host of origin may not be blank");
+ }
+ if (port < 0) {
+ throw new IllegalArgumentException("Invalid port: " + port);
+ }
+ if (path == null) {
+ throw new IllegalArgumentException(
+ "Path of origin may not be null.");
+ }
+ this.host = host.toLowerCase(Locale.ENGLISH);
+ this.port = port;
+ if (path.trim().length() != 0) {
+ this.path = path;
+ } else {
+ this.path = "/";
+ }
+ this.secure = secure;
+ }
+
+ public String getHost() {
+ return this.host;
+ }
+
+ public String getPath() {
+ return this.path;
+ }
+
+ public int getPort() {
+ return this.port;
+ }
+
+ public boolean isSecure() {
+ return this.secure;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append('[');
+ if (this.secure) {
+ buffer.append("(secure)");
+ }
+ buffer.append(this.host);
+ buffer.append(':');
+ buffer.append(Integer.toString(this.port));
+ buffer.append(this.path);
+ buffer.append(']');
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/cookie/CookiePathComparator.java b/src/org/apache/http/cookie/CookiePathComparator.java
new file mode 100644
index 0000000..f5f0a66
--- /dev/null
+++ b/src/org/apache/http/cookie/CookiePathComparator.java
@@ -0,0 +1,81 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookiePathComparator.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * This cookie comparator ensures that multiple cookies satisfying
+ * a common criteria are ordered in the <tt>Cookie</tt> header such
+ * that those with more specific Path attributes precede those with
+ * less specific.
+ *
+ * <p>
+ * This comparator assumes that Path attributes of two cookies
+ * path-match a commmon request-URI. Otherwise, the result of the
+ * comparison is undefined.
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class CookiePathComparator implements Serializable, Comparator<Cookie> {
+
+ private static final long serialVersionUID = 7523645369616405818L;
+
+ private String normalizePath(final Cookie cookie) {
+ String path = cookie.getPath();
+ if (path == null) {
+ path = "/";
+ }
+ if (!path.endsWith("/")) {
+ path = path + '/';
+ }
+ return path;
+ }
+
+ public int compare(final Cookie c1, final Cookie c2) {
+ String path1 = normalizePath(c1);
+ String path2 = normalizePath(c2);
+ if (path1.equals(path2)) {
+ return 0;
+ } else if (path1.startsWith(path2)) {
+ return -1;
+ } else if (path2.startsWith(path1)) {
+ return 1;
+ } else {
+ // Does not really matter
+ return 0;
+ }
+ }
+
+}
diff --git a/src/org/apache/http/cookie/CookieSpec.java b/src/org/apache/http/cookie/CookieSpec.java
new file mode 100644
index 0000000..1eb9f26
--- /dev/null
+++ b/src/org/apache/http/cookie/CookieSpec.java
@@ -0,0 +1,115 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookieSpec.java $
+ * $Revision: 603563 $
+ * $Date: 2007-12-12 03:17:55 -0800 (Wed, 12 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.util.List;
+
+import org.apache.http.Header;
+
+/**
+ * Defines the cookie management specification.
+ * <p>Cookie management specification must define
+ * <ul>
+ * <li> rules of parsing "Set-Cookie" header
+ * <li> rules of validation of parsed cookies
+ * <li> formatting of "Cookie" header
+ * </ul>
+ * for a given host, port and path of origin
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ *
+ * @since 4.0
+ */
+public interface CookieSpec {
+
+ /**
+ * Returns version of the state management this cookie specification
+ * conforms to.
+ *
+ * @return version of the state management specification
+ */
+ int getVersion();
+
+ /**
+ * Parse the <tt>"Set-Cookie"</tt> Header into an array of Cookies.
+ *
+ * <p>This method will not perform the validation of the resultant
+ * {@link Cookie}s</p>
+ *
+ * @see #validate
+ *
+ * @param header the <tt>Set-Cookie</tt> received from the server
+ * @param origin details of the cookie origin
+ * @return an array of <tt>Cookie</tt>s parsed from the header
+ * @throws MalformedCookieException if an exception occurs during parsing
+ */
+ List<Cookie> parse(Header header, CookieOrigin origin) throws MalformedCookieException;
+
+ /**
+ * Validate the cookie according to validation rules defined by the
+ * cookie specification.
+ *
+ * @param cookie the Cookie to validate
+ * @param origin details of the cookie origin
+ * @throws MalformedCookieException if the cookie is invalid
+ */
+ void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException;
+
+ /**
+ * Determines if a Cookie matches the target location.
+ *
+ * @param cookie the Cookie to be matched
+ * @param origin the target to test against
+ *
+ * @return <tt>true</tt> if the cookie should be submitted with a request
+ * with given attributes, <tt>false</tt> otherwise.
+ */
+ boolean match(Cookie cookie, CookieOrigin origin);
+
+ /**
+ * Create <tt>"Cookie"</tt> headers for an array of Cookies.
+ *
+ * @param cookies the Cookies format into a Cookie header
+ * @return a Header for the given Cookies.
+ * @throws IllegalArgumentException if an input parameter is illegal
+ */
+ List<Header> formatCookies(List<Cookie> cookies);
+
+ /**
+ * Returns a request header identifying what version of the state management
+ * specification is understood. May be <code>null</code> if the cookie
+ * specification does not support <tt>Cookie2</tt> header.
+ */
+ Header getVersionHeader();
+
+}
diff --git a/src/org/apache/http/cookie/CookieSpecFactory.java b/src/org/apache/http/cookie/CookieSpecFactory.java
new file mode 100644
index 0000000..9d5c21d
--- /dev/null
+++ b/src/org/apache/http/cookie/CookieSpecFactory.java
@@ -0,0 +1,46 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookieSpecFactory.java $
+ * $Revision: 489636 $
+ * $Date: 2006-12-22 04:34:57 -0800 (Fri, 22 Dec 2006) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface CookieSpecFactory {
+
+ CookieSpec newInstance(HttpParams params);
+
+}
diff --git a/src/org/apache/http/cookie/CookieSpecRegistry.java b/src/org/apache/http/cookie/CookieSpecRegistry.java
new file mode 100644
index 0000000..64b9c8b
--- /dev/null
+++ b/src/org/apache/http/cookie/CookieSpecRegistry.java
@@ -0,0 +1,160 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/CookieSpecRegistry.java $
+ * $Revision: 652950 $
+ * $Date: 2008-05-02 16:49:48 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ * Cookie specification registry that can be used to obtain the corresponding
+ * cookie specification implementation for a given type of type or version of
+ * cookie.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @since 4.0
+ */
+public final class CookieSpecRegistry {
+
+ private final Map<String,CookieSpecFactory> registeredSpecs;
+
+ public CookieSpecRegistry() {
+ super();
+ this.registeredSpecs = new LinkedHashMap<String,CookieSpecFactory>();
+ }
+
+ /**
+ * Registers a {@link CookieSpecFactory} with the given identifier.
+ * If a specification with the given name already exists it will be overridden.
+ * This nameis the same one used to retrieve the {@link CookieSpecFactory}
+ * from {@link #getCookieSpec(String)}.
+ *
+ * @param name the identifier for this specification
+ * @param factory the {@link CookieSpecFactory} class to register
+ *
+ * @see #getCookieSpec(String)
+ */
+ public synchronized void register(final String name, final CookieSpecFactory factory) {
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ if (factory == null) {
+ throw new IllegalArgumentException("Cookie spec factory may not be null");
+ }
+ registeredSpecs.put(name.toLowerCase(Locale.ENGLISH), factory);
+ }
+
+ /**
+ * Unregisters the {@link CookieSpecFactory} with the given ID.
+ *
+ * @param id the identifier of the {@link CookieSpec cookie specification} to unregister
+ */
+ public synchronized void unregister(final String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("Id may not be null");
+ }
+ registeredSpecs.remove(id.toLowerCase(Locale.ENGLISH));
+ }
+
+ /**
+ * Gets the {@link CookieSpec cookie specification} with the given ID.
+ *
+ * @param name the {@link CookieSpec cookie specification} identifier
+ * @param params the {@link HttpParams HTTP parameters} for the cookie
+ * specification.
+ *
+ * @return {@link CookieSpec cookie specification}
+ *
+ * @throws IllegalStateException if a policy with the given name cannot be found
+ */
+ public synchronized CookieSpec getCookieSpec(final String name, final HttpParams params)
+ throws IllegalStateException {
+
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ CookieSpecFactory factory = registeredSpecs.get(name.toLowerCase(Locale.ENGLISH));
+ if (factory != null) {
+ return factory.newInstance(params);
+ } else {
+ throw new IllegalStateException("Unsupported cookie spec: " + name);
+ }
+ }
+
+ /**
+ * Gets the {@link CookieSpec cookie specification} with the given name.
+ *
+ * @param name the {@link CookieSpec cookie specification} identifier
+ *
+ * @return {@link CookieSpec cookie specification}
+ *
+ * @throws IllegalStateException if a policy with the given name cannot be found
+ */
+ public synchronized CookieSpec getCookieSpec(final String name)
+ throws IllegalStateException {
+ return getCookieSpec(name, null);
+ }
+
+ /**
+ * Obtains a list containing names of all registered {@link CookieSpec cookie
+ * specs} in their default order.
+ *
+ * Note that the DEFAULT policy (if present) is likely to be the same
+ * as one of the other policies, but does not have to be.
+ *
+ * @return list of registered cookie spec names
+ */
+ public synchronized List<String> getSpecNames(){
+ return new ArrayList<String>(registeredSpecs.keySet());
+ }
+
+ /**
+ * Populates the internal collection of registered {@link CookieSpec cookie
+ * specs} with the content of the map passed as a parameter.
+ *
+ * @param map cookie specs
+ */
+ public synchronized void setItems(final Map<String, CookieSpecFactory> map) {
+ if (map == null) {
+ return;
+ }
+ registeredSpecs.clear();
+ registeredSpecs.putAll(map);
+ }
+
+}
diff --git a/src/org/apache/http/cookie/MalformedCookieException.java b/src/org/apache/http/cookie/MalformedCookieException.java
new file mode 100644
index 0000000..e3f30a9
--- /dev/null
+++ b/src/org/apache/http/cookie/MalformedCookieException.java
@@ -0,0 +1,74 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/MalformedCookieException.java $
+ * $Revision: 508891 $
+ * $Date: 2007-02-18 02:08:48 -0800 (Sun, 18 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import org.apache.http.ProtocolException;
+
+/**
+ * Signals that a cookie is in some way invalid or illegal in a given
+ * context
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class MalformedCookieException extends ProtocolException {
+
+ private static final long serialVersionUID = -6695462944287282185L;
+
+ /**
+ * Creates a new MalformedCookieException with a <tt>null</tt> detail message.
+ */
+ public MalformedCookieException() {
+ super();
+ }
+
+ /**
+ * Creates a new MalformedCookieException with a specified message string.
+ *
+ * @param message The exception detail message
+ */
+ public MalformedCookieException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new MalformedCookieException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public MalformedCookieException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/cookie/SM.java b/src/org/apache/http/cookie/SM.java
new file mode 100644
index 0000000..a7047d5
--- /dev/null
+++ b/src/org/apache/http/cookie/SM.java
@@ -0,0 +1,48 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/SM.java $
+ * $Revision: 582602 $
+ * $Date: 2007-10-07 02:35:48 -0700 (Sun, 07 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+/**
+ * Constants and static helpers related to the HTTP state management.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface SM {
+
+ public static final String COOKIE = "Cookie";
+ public static final String COOKIE2 = "Cookie2";
+ public static final String SET_COOKIE = "Set-Cookie";
+ public static final String SET_COOKIE2 = "Set-Cookie2";
+
+}
diff --git a/src/org/apache/http/cookie/SetCookie.java b/src/org/apache/http/cookie/SetCookie.java
new file mode 100644
index 0000000..d207c48
--- /dev/null
+++ b/src/org/apache/http/cookie/SetCookie.java
@@ -0,0 +1,115 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/SetCookie.java $
+ * $Revision: 617193 $
+ * $Date: 2008-01-31 11:26:47 -0800 (Thu, 31 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.util.Date;
+
+/**
+ * This interface represents a <code>SetCookie</code> response header sent by the
+ * origin server to the HTTP agent in order to maintain a conversational state.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface SetCookie extends Cookie {
+
+ void setValue(String value);
+
+ /**
+ * If a user agent (web browser) presents this cookie to a user, the
+ * cookie's purpose will be described using this comment.
+ *
+ * @param comment
+ *
+ * @see #getComment()
+ */
+ void setComment(String comment);
+
+ /**
+ * Sets expiration date.
+ * <p><strong>Note:</strong> the object returned by this method is considered
+ * immutable. Changing it (e.g. using setTime()) could result in undefined
+ * behaviour. Do so at your peril.</p>
+ *
+ * @param expiryDate the {@link Date} after which this cookie is no longer valid.
+ *
+ * @see Cookie#getExpiryDate
+ *
+ */
+ void setExpiryDate (Date expiryDate);
+
+ /**
+ * Sets the domain attribute.
+ *
+ * @param domain The value of the domain attribute
+ *
+ * @see Cookie#getDomain
+ */
+ void setDomain(String domain);
+
+ /**
+ * Sets the path attribute.
+ *
+ * @param path The value of the path attribute
+ *
+ * @see Cookie#getPath
+ *
+ */
+ void setPath(String path);
+
+ /**
+ * Sets the secure attribute of the cookie.
+ * <p>
+ * When <tt>true</tt> the cookie should only be sent
+ * using a secure protocol (https). This should only be set when
+ * the cookie's originating server used a secure protocol to set the
+ * cookie's value.
+ *
+ * @param secure The value of the secure attribute
+ *
+ * @see #isSecure()
+ */
+ void setSecure (boolean secure);
+
+ /**
+ * Sets the version of the cookie specification to which this
+ * cookie conforms.
+ *
+ * @param version the version of the cookie.
+ *
+ * @see Cookie#getVersion
+ */
+ void setVersion(int version);
+
+}
+
diff --git a/src/org/apache/http/cookie/SetCookie2.java b/src/org/apache/http/cookie/SetCookie2.java
new file mode 100644
index 0000000..cd0420e
--- /dev/null
+++ b/src/org/apache/http/cookie/SetCookie2.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/SetCookie2.java $
+ * $Revision: 578408 $
+ * $Date: 2007-09-22 04:53:57 -0700 (Sat, 22 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+/**
+ * This interface represents a <code>SetCookie2</code> response header sent by the
+ * origin server to the HTTP agent in order to maintain a conversational state.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface SetCookie2 extends SetCookie {
+
+ /**
+ * If a user agent (web browser) presents this cookie to a user, the
+ * cookie's purpose will be described by the information at this URL.
+ */
+ void setCommentURL(String commentURL);
+
+ /**
+ * Sets the Port attribute. It restricts the ports to which a cookie
+ * may be returned in a Cookie request header.
+ */
+ void setPorts(int[] ports);
+
+ /**
+ * Set the Discard attribute.
+ *
+ * Note: <tt>Discard</tt> attribute overrides <tt>Max-age</tt>.
+ *
+ * @see #isPersistent()
+ */
+ void setDiscard(boolean discard);
+
+}
+
diff --git a/src/org/apache/http/cookie/package.html b/src/org/apache/http/cookie/package.html
new file mode 100644
index 0000000..891d9c3
--- /dev/null
+++ b/src/org/apache/http/cookie/package.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The API for client-side state management via cookies,
+commonly referred to as <i>HttpCookie</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/cookie/params/CookieSpecPNames.java b/src/org/apache/http/cookie/params/CookieSpecPNames.java
new file mode 100644
index 0000000..6a6f6d0
--- /dev/null
+++ b/src/org/apache/http/cookie/params/CookieSpecPNames.java
@@ -0,0 +1,68 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/params/CookieSpecPNames.java $
+ * $Revision: 578403 $
+ * $Date: 2007-09-22 03:56:04 -0700 (Sat, 22 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie.params;
+
+/**
+ * Parameter names for cookie specifications in HttpCookie.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 578403 $
+ *
+ * @since 4.0
+ */
+public interface CookieSpecPNames {
+
+ /**
+ * Parameter for the date patterns used for parsing.
+ * <p>
+ * This parameter expects a value of type {@link java.util.Collection}.
+ * The collection elements are of type {@link String}
+ * and must be compatible with the syntax of
+ * {@link java.text.SimpleDateFormat}.
+ * </p>
+ */
+ public static final String DATE_PATTERNS = "http.protocol.cookie-datepatterns";
+
+ /**
+ * Parameter for Cookie header formatting.
+ * Defines whether {@link org.apache.http.cookie.Cookie cookies}
+ * should be put on
+ * a single {@link org.apache.http.Header request header}.
+ * If not, each cookie is formatted in a seperate Cookie header.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
+
+}
diff --git a/src/org/apache/http/cookie/params/CookieSpecParamBean.java b/src/org/apache/http/cookie/params/CookieSpecParamBean.java
new file mode 100644
index 0000000..6016022
--- /dev/null
+++ b/src/org/apache/http/cookie/params/CookieSpecParamBean.java
@@ -0,0 +1,53 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/params/CookieSpecParamBean.java $
+ * $Revision: 632313 $
+ * $Date: 2008-02-29 05:19:50 -0800 (Fri, 29 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie.params;
+
+import java.util.Collection;
+
+import org.apache.http.params.HttpAbstractParamBean;
+import org.apache.http.params.HttpParams;
+
+public class CookieSpecParamBean extends HttpAbstractParamBean {
+
+ public CookieSpecParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ public void setDatePatterns (final Collection <String> patterns) {
+ params.setParameter(CookieSpecPNames.DATE_PATTERNS, patterns);
+ }
+
+ public void setSingleHeader (final boolean singleHeader) {
+ params.setBooleanParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, singleHeader);
+ }
+
+}
diff --git a/src/org/apache/http/cookie/params/package.html b/src/org/apache/http/cookie/params/package.html
new file mode 100644
index 0000000..e6fb7cd
--- /dev/null
+++ b/src/org/apache/http/cookie/params/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/cookie/params/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Parameters for configuring <i>HttpCookie</i>.
+
+</body>
+</html>
diff --git a/src/org/apache/http/entity/AbstractHttpEntity.java b/src/org/apache/http/entity/AbstractHttpEntity.java
new file mode 100644
index 0000000..0fce6eb
--- /dev/null
+++ b/src/org/apache/http/entity/AbstractHttpEntity.java
@@ -0,0 +1,213 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/AbstractHttpEntity.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.IOException;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Abstract base class for entities.
+ * Provides the commonly used attributes for streamed and self-contained
+ * implementations of {@link HttpEntity HttpEntity}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractHttpEntity implements HttpEntity {
+
+ /**
+ * The Content-Type header.
+ * Returned by {@link #getContentType getContentType},
+ * unless that method is overridden.
+ */
+ protected Header contentType;
+
+ /**
+ * The Content-Encoding header.
+ * Returned by {@link #getContentEncoding getContentEncoding},
+ * unless that method is overridden.
+ */
+ protected Header contentEncoding;
+
+ /**
+ * The 'chunked' flag.
+ * Returned by {@link #isChunked isChunked},
+ * unless that method is overridden.
+ */
+ protected boolean chunked;
+
+
+ /**
+ * Protected default constructor.
+ * The attributes of the created object remain
+ * <code>null</code> and <code>false</code>, respectively.
+ */
+ protected AbstractHttpEntity() {
+ super();
+ }
+
+
+ /**
+ * Obtains the Content-Type header.
+ * The default implementation returns the value of the
+ * {@link #contentType contentType} attribute.
+ *
+ * @return the Content-Type header, or <code>null</code>
+ */
+ public Header getContentType() {
+ return this.contentType;
+ }
+
+
+ /**
+ * Obtains the Content-Encoding header.
+ * The default implementation returns the value of the
+ * {@link #contentEncoding contentEncoding} attribute.
+ *
+ * @return the Content-Encoding header, or <code>null</code>
+ */
+ public Header getContentEncoding() {
+ return this.contentEncoding;
+ }
+
+ /**
+ * Obtains the 'chunked' flag.
+ * The default implementation returns the value of the
+ * {@link #chunked chunked} attribute.
+ *
+ * @return the 'chunked' flag
+ */
+ public boolean isChunked() {
+ return this.chunked;
+ }
+
+
+ /**
+ * Specifies the Content-Type header.
+ * The default implementation sets the value of the
+ * {@link #contentType contentType} attribute.
+ *
+ * @param contentType the new Content-Encoding header, or
+ * <code>null</code> to unset
+ */
+ public void setContentType(final Header contentType) {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Specifies the Content-Type header, as a string.
+ * The default implementation calls
+ * {@link #setContentType(Header) setContentType(Header)}.
+ *
+ * @param ctString the new Content-Type header, or
+ * <code>null</code> to unset
+ */
+ public void setContentType(final String ctString) {
+ Header h = null;
+ if (ctString != null) {
+ h = new BasicHeader(HTTP.CONTENT_TYPE, ctString);
+ }
+ setContentType(h);
+ }
+
+
+ /**
+ * Specifies the Content-Encoding header.
+ * The default implementation sets the value of the
+ * {@link #contentEncoding contentEncoding} attribute.
+ *
+ * @param contentEncoding the new Content-Encoding header, or
+ * <code>null</code> to unset
+ */
+ public void setContentEncoding(final Header contentEncoding) {
+ this.contentEncoding = contentEncoding;
+ }
+
+ /**
+ * Specifies the Content-Encoding header, as a string.
+ * The default implementation calls
+ * {@link #setContentEncoding(Header) setContentEncoding(Header)}.
+ *
+ * @param ceString the new Content-Encoding header, or
+ * <code>null</code> to unset
+ */
+ public void setContentEncoding(final String ceString) {
+ Header h = null;
+ if (ceString != null) {
+ h = new BasicHeader(HTTP.CONTENT_ENCODING, ceString);
+ }
+ setContentEncoding(h);
+ }
+
+
+ /**
+ * Specifies the 'chunked' flag.
+ * The default implementation sets the value of the
+ * {@link #chunked chunked} attribute.
+ *
+ * @param b the new 'chunked' flag
+ */
+ public void setChunked(boolean b) {
+ this.chunked = b;
+ }
+
+
+ /**
+ * Does not consume anything.
+ * The default implementation does nothing if
+ * {@link HttpEntity#isStreaming isStreaming}
+ * returns <code>false</code>, and throws an exception
+ * if it returns <code>true</code>.
+ * This removes the burden of implementing
+ * an empty method for non-streaming entities.
+ *
+ * @throws IOException in case of an I/O problem
+ * @throws UnsupportedOperationException
+ * if a streaming subclass does not override this method
+ */
+ public void consumeContent()
+ throws IOException, UnsupportedOperationException{
+ if (isStreaming()) {
+ throw new UnsupportedOperationException
+ ("streaming entity does not implement consumeContent()");
+ }
+ } // consumeContent
+
+
+} // class AbstractHttpEntity
diff --git a/src/org/apache/http/entity/BasicHttpEntity.java b/src/org/apache/http/entity/BasicHttpEntity.java
new file mode 100644
index 0000000..df3c07c
--- /dev/null
+++ b/src/org/apache/http/entity/BasicHttpEntity.java
@@ -0,0 +1,146 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/BasicHttpEntity.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A generic streamed entity being received on a connection.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpEntity extends AbstractHttpEntity {
+
+ private InputStream content;
+ private boolean contentObtained;
+ private long length;
+
+ /**
+ * Creates a new basic entity.
+ * The content is initially missing, the content length
+ * is set to a negative number.
+ */
+ public BasicHttpEntity() {
+ super();
+ this.length = -1;
+ }
+
+ // non-javadoc, see interface HttpEntity
+ public long getContentLength() {
+ return this.length;
+ }
+
+ /**
+ * Obtains the content, once only.
+ *
+ * @return the content, if this is the first call to this method
+ * since {@link #setContent setContent} has been called
+ *
+ * @throws IllegalStateException
+ * if the content has been obtained before, or
+ * has not yet been provided
+ */
+ public InputStream getContent()
+ throws IllegalStateException {
+ if (this.content == null) {
+ throw new IllegalStateException("Content has not been provided");
+ }
+ if (this.contentObtained) {
+ throw new IllegalStateException("Content has been consumed");
+ }
+ this.contentObtained = true;
+ return this.content;
+
+ } // getContent
+
+ /**
+ * Tells that this entity is not repeatable.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isRepeatable() {
+ return false;
+ }
+
+ /**
+ * Specifies the length of the content.
+ *
+ * @param len the number of bytes in the content, or
+ * a negative number to indicate an unknown length
+ */
+ public void setContentLength(long len) {
+ this.length = len;
+ }
+
+ /**
+ * Specifies the content.
+ *
+ * @param instream the stream to return with the next call to
+ * {@link #getContent getContent}
+ */
+ public void setContent(final InputStream instream) {
+ this.content = instream;
+ this.contentObtained = false;
+ }
+
+ // non-javadoc, see interface HttpEntity
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ InputStream instream = getContent();
+ int l;
+ byte[] tmp = new byte[2048];
+ while ((l = instream.read(tmp)) != -1) {
+ outstream.write(tmp, 0, l);
+ }
+ }
+
+ // non-javadoc, see interface HttpEntity
+ public boolean isStreaming() {
+ return !this.contentObtained && this.content != null;
+ }
+
+ // non-javadoc, see interface HttpEntity
+ public void consumeContent() throws IOException {
+ if (content != null) {
+ content.close(); // reads to the end of the entity
+ }
+ }
+
+} // class BasicHttpEntity
diff --git a/src/org/apache/http/entity/BufferedHttpEntity.java b/src/org/apache/http/entity/BufferedHttpEntity.java
new file mode 100644
index 0000000..9888797
--- /dev/null
+++ b/src/org/apache/http/entity/BufferedHttpEntity.java
@@ -0,0 +1,120 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/BufferedHttpEntity.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * A wrapping entity that buffers it content if necessary.
+ * The buffered entity is always repeatable.
+ * If the wrapped entity is repeatable itself, calls are passed through.
+ * If the wrapped entity is not repeatable, the content is read into a
+ * buffer once and provided from there as often as required.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public class BufferedHttpEntity extends HttpEntityWrapper {
+
+ private final byte[] buffer;
+
+ public BufferedHttpEntity(final HttpEntity entity) throws IOException {
+ super(entity);
+ if (!entity.isRepeatable() || entity.getContentLength() < 0) {
+ this.buffer = EntityUtils.toByteArray(entity);
+ } else {
+ this.buffer = null;
+ }
+ }
+
+ public long getContentLength() {
+ if (this.buffer != null) {
+ return this.buffer.length;
+ } else {
+ return wrappedEntity.getContentLength();
+ }
+ }
+
+ public InputStream getContent() throws IOException {
+ if (this.buffer != null) {
+ return new ByteArrayInputStream(this.buffer);
+ } else {
+ return wrappedEntity.getContent();
+ }
+ }
+
+ /**
+ * Tells that this entity does not have to be chunked.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isChunked() {
+ return (buffer == null) && wrappedEntity.isChunked();
+ }
+
+ /**
+ * Tells that this entity is repeatable.
+ *
+ * @return <code>true</code>
+ */
+ public boolean isRepeatable() {
+ return true;
+ }
+
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ if (this.buffer != null) {
+ outstream.write(this.buffer);
+ } else {
+ wrappedEntity.writeTo(outstream);
+ }
+ }
+
+
+ // non-javadoc, see interface HttpEntity
+ public boolean isStreaming() {
+ return (buffer == null) && wrappedEntity.isStreaming();
+ }
+
+} // class BufferedHttpEntity
diff --git a/src/org/apache/http/entity/ByteArrayEntity.java b/src/org/apache/http/entity/ByteArrayEntity.java
new file mode 100644
index 0000000..c7257f7
--- /dev/null
+++ b/src/org/apache/http/entity/ByteArrayEntity.java
@@ -0,0 +1,94 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/ByteArrayEntity.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An entity whose content is retrieved from a byte array.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 604625 $
+ *
+ * @since 4.0
+ */
+public class ByteArrayEntity extends AbstractHttpEntity implements Cloneable {
+
+ protected final byte[] content;
+
+ public ByteArrayEntity(final byte[] b) {
+ super();
+ if (b == null) {
+ throw new IllegalArgumentException("Source byte array may not be null");
+ }
+ this.content = b;
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ public long getContentLength() {
+ return this.content.length;
+ }
+
+ public InputStream getContent() {
+ return new ByteArrayInputStream(this.content);
+ }
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ outstream.write(this.content);
+ outstream.flush();
+ }
+
+
+ /**
+ * Tells that this entity is not streaming.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isStreaming() {
+ return false;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+} // class ByteArrayEntity
diff --git a/src/org/apache/http/entity/ContentLengthStrategy.java b/src/org/apache/http/entity/ContentLengthStrategy.java
new file mode 100644
index 0000000..cc4ab7d
--- /dev/null
+++ b/src/org/apache/http/entity/ContentLengthStrategy.java
@@ -0,0 +1,54 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/ContentLengthStrategy.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+
+/**
+ * Represents a strategy to determine the content length based on the properties
+ * of an HTTP message.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 613298 $
+ *
+ * @since 4.0
+ */
+public interface ContentLengthStrategy {
+
+ public static final int IDENTITY = -1;
+ public static final int CHUNKED = -2;
+
+ long determineLength(HttpMessage message) throws HttpException;
+
+}
diff --git a/src/org/apache/http/entity/ContentProducer.java b/src/org/apache/http/entity/ContentProducer.java
new file mode 100644
index 0000000..456eae3
--- /dev/null
+++ b/src/org/apache/http/entity/ContentProducer.java
@@ -0,0 +1,53 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/ContentProducer.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An abstract entity content producer.
+ *
+ *<p>Content producers are expected to be able to produce their
+ * content multiple times</p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public interface ContentProducer {
+
+ void writeTo(OutputStream outstream) throws IOException;
+
+}
diff --git a/src/org/apache/http/entity/EntityTemplate.java b/src/org/apache/http/entity/EntityTemplate.java
new file mode 100644
index 0000000..0c6002e
--- /dev/null
+++ b/src/org/apache/http/entity/EntityTemplate.java
@@ -0,0 +1,86 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/EntityTemplate.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Entity that delegates the process of content generation to an abstract
+ * content producer.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public class EntityTemplate extends AbstractHttpEntity {
+
+ private final ContentProducer contentproducer;
+
+ public EntityTemplate(final ContentProducer contentproducer) {
+ super();
+ if (contentproducer == null) {
+ throw new IllegalArgumentException("Content producer may not be null");
+ }
+ this.contentproducer = contentproducer;
+ }
+
+ public long getContentLength() {
+ return -1;
+ }
+
+ public InputStream getContent() {
+ throw new UnsupportedOperationException("Entity template does not implement getContent()");
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ this.contentproducer.writeTo(outstream);
+ }
+
+ public boolean isStreaming() {
+ return true;
+ }
+
+ public void consumeContent() throws IOException {
+ }
+
+}
diff --git a/src/org/apache/http/entity/FileEntity.java b/src/org/apache/http/entity/FileEntity.java
new file mode 100644
index 0000000..a991058
--- /dev/null
+++ b/src/org/apache/http/entity/FileEntity.java
@@ -0,0 +1,106 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/FileEntity.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An entity whose content is retrieved from a file.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 604625 $
+ *
+ * @since 4.0
+ */
+public class FileEntity extends AbstractHttpEntity implements Cloneable {
+
+ protected final File file;
+
+ public FileEntity(final File file, final String contentType) {
+ super();
+ if (file == null) {
+ throw new IllegalArgumentException("File may not be null");
+ }
+ this.file = file;
+ setContentType(contentType);
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ public long getContentLength() {
+ return this.file.length();
+ }
+
+ public InputStream getContent() throws IOException {
+ return new FileInputStream(this.file);
+ }
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ InputStream instream = new FileInputStream(this.file);
+ try {
+ byte[] tmp = new byte[4096];
+ int l;
+ while ((l = instream.read(tmp)) != -1) {
+ outstream.write(tmp, 0, l);
+ }
+ outstream.flush();
+ } finally {
+ instream.close();
+ }
+ }
+
+ /**
+ * Tells that this entity is not streaming.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isStreaming() {
+ return false;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ // File instance is considered immutable
+ // No need to make a copy of it
+ return super.clone();
+ }
+
+} // class FileEntity
diff --git a/src/org/apache/http/entity/HttpEntityWrapper.java b/src/org/apache/http/entity/HttpEntityWrapper.java
new file mode 100644
index 0000000..17a4149
--- /dev/null
+++ b/src/org/apache/http/entity/HttpEntityWrapper.java
@@ -0,0 +1,113 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/HttpEntityWrapper.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+
+/**
+ * Base class for wrapping entities.
+ * Keeps a {@link #wrappedEntity wrappedEntity} and delegates all
+ * calls to it. Implementations of wrapping entities can derive
+ * from this class and need to override only those methods that
+ * should not be delegated to the wrapped entity.
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public class HttpEntityWrapper implements HttpEntity {
+
+ /** The wrapped entity. */
+ protected HttpEntity wrappedEntity;
+
+ /**
+ * Creates a new entity wrapper.
+ *
+ * @param wrapped the entity to wrap
+ */
+ public HttpEntityWrapper(HttpEntity wrapped) {
+ super();
+
+ if (wrapped == null) {
+ throw new IllegalArgumentException
+ ("wrapped entity must not be null");
+ }
+ wrappedEntity = wrapped;
+
+ } // constructor
+
+
+ public boolean isRepeatable() {
+ return wrappedEntity.isRepeatable();
+ }
+
+ public boolean isChunked() {
+ return wrappedEntity.isChunked();
+ }
+
+ public long getContentLength() {
+ return wrappedEntity.getContentLength();
+ }
+
+ public Header getContentType() {
+ return wrappedEntity.getContentType();
+ }
+
+ public Header getContentEncoding() {
+ return wrappedEntity.getContentEncoding();
+ }
+
+ public InputStream getContent()
+ throws IOException {
+ return wrappedEntity.getContent();
+ }
+
+ public void writeTo(OutputStream outstream)
+ throws IOException {
+ wrappedEntity.writeTo(outstream);
+ }
+
+ public boolean isStreaming() {
+ return wrappedEntity.isStreaming();
+ }
+
+ public void consumeContent()
+ throws IOException {
+ wrappedEntity.consumeContent();
+ }
+
+} // class HttpEntityWrapper
diff --git a/src/org/apache/http/entity/InputStreamEntity.java b/src/org/apache/http/entity/InputStreamEntity.java
new file mode 100644
index 0000000..6d33fe4
--- /dev/null
+++ b/src/org/apache/http/entity/InputStreamEntity.java
@@ -0,0 +1,116 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/InputStreamEntity.java $
+ * $Revision: 617591 $
+ * $Date: 2008-02-01 10:21:17 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A streamed entity obtaining content from an {@link InputStream InputStream}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 617591 $
+ *
+ * @since 4.0
+ */
+public class InputStreamEntity extends AbstractHttpEntity {
+
+ private final static int BUFFER_SIZE = 2048;
+
+ private final InputStream content;
+ private final long length;
+ private boolean consumed = false;
+
+ public InputStreamEntity(final InputStream instream, long length) {
+ super();
+ if (instream == null) {
+ throw new IllegalArgumentException("Source input stream may not be null");
+ }
+ this.content = instream;
+ this.length = length;
+ }
+
+ public boolean isRepeatable() {
+ return false;
+ }
+
+ public long getContentLength() {
+ return this.length;
+ }
+
+ public InputStream getContent() throws IOException {
+ return this.content;
+ }
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ InputStream instream = this.content;
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int l;
+ if (this.length < 0) {
+ // consume until EOF
+ while ((l = instream.read(buffer)) != -1) {
+ outstream.write(buffer, 0, l);
+ }
+ } else {
+ // consume no more than length
+ long remaining = this.length;
+ while (remaining > 0) {
+ l = instream.read(buffer, 0, (int)Math.min(BUFFER_SIZE, remaining));
+ if (l == -1) {
+ break;
+ }
+ outstream.write(buffer, 0, l);
+ remaining -= l;
+ }
+ }
+ this.consumed = true;
+ }
+
+ // non-javadoc, see interface HttpEntity
+ public boolean isStreaming() {
+ return !this.consumed;
+ }
+
+ // non-javadoc, see interface HttpEntity
+ public void consumeContent() throws IOException {
+ this.consumed = true;
+ // If the input stream is from a connection, closing it will read to
+ // the end of the content. Otherwise, we don't care what it does.
+ this.content.close();
+ }
+
+} // class InputStreamEntity
diff --git a/src/org/apache/http/entity/SerializableEntity.java b/src/org/apache/http/entity/SerializableEntity.java
new file mode 100644
index 0000000..171977b
--- /dev/null
+++ b/src/org/apache/http/entity/SerializableEntity.java
@@ -0,0 +1,107 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/SerializableEntity.java $
+ * $Revision: 647816 $
+ * $Date: 2008-04-14 07:37:13 -0700 (Mon, 14 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+public class SerializableEntity extends AbstractHttpEntity {
+
+ private byte[] objSer;
+
+ private Serializable objRef;
+
+ public SerializableEntity(Serializable ser, boolean bufferize) throws IOException {
+ super();
+ if (ser == null) {
+ throw new IllegalArgumentException("Source object may not be null");
+ }
+
+ if (bufferize) {
+ createBytes(ser);
+ } else {
+ this.objRef = ser;
+ }
+ }
+
+ private void createBytes(Serializable ser) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(baos);
+ out.writeObject(ser);
+ out.flush();
+ this.objSer = baos.toByteArray();
+ }
+
+ public InputStream getContent() throws IOException, IllegalStateException {
+ if (this.objSer == null) {
+ createBytes(this.objRef);
+ }
+ return new ByteArrayInputStream(this.objSer);
+ }
+
+ public long getContentLength() {
+ if (this.objSer == null) {
+ return -1;
+ } else {
+ return this.objSer.length;
+ }
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ public boolean isStreaming() {
+ return this.objSer == null;
+ }
+
+ public void writeTo(OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+
+ if (this.objSer == null) {
+ ObjectOutputStream out = new ObjectOutputStream(outstream);
+ out.writeObject(this.objRef);
+ out.flush();
+ } else {
+ outstream.write(this.objSer);
+ outstream.flush();
+ }
+ }
+
+}
diff --git a/src/org/apache/http/entity/StringEntity.java b/src/org/apache/http/entity/StringEntity.java
new file mode 100644
index 0000000..cbc382b
--- /dev/null
+++ b/src/org/apache/http/entity/StringEntity.java
@@ -0,0 +1,106 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/StringEntity.java $
+ * $Revision: 618367 $
+ * $Date: 2008-02-04 10:26:06 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.http.protocol.HTTP;
+
+/**
+ * An entity whose content is retrieved from a string.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618367 $
+ *
+ * @since 4.0
+ */
+public class StringEntity extends AbstractHttpEntity implements Cloneable {
+
+ protected final byte[] content;
+
+ public StringEntity(final String s, String charset)
+ throws UnsupportedEncodingException {
+ super();
+ if (s == null) {
+ throw new IllegalArgumentException("Source string may not be null");
+ }
+ if (charset == null) {
+ charset = HTTP.DEFAULT_CONTENT_CHARSET;
+ }
+ this.content = s.getBytes(charset);
+ setContentType(HTTP.PLAIN_TEXT_TYPE + HTTP.CHARSET_PARAM + charset);
+ }
+
+ public StringEntity(final String s)
+ throws UnsupportedEncodingException {
+ this(s, null);
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ public long getContentLength() {
+ return this.content.length;
+ }
+
+ public InputStream getContent() throws IOException {
+ return new ByteArrayInputStream(this.content);
+ }
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ outstream.write(this.content);
+ outstream.flush();
+ }
+
+ /**
+ * Tells that this entity is not streaming.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isStreaming() {
+ return false;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+} // class StringEntity
diff --git a/src/org/apache/http/entity/package.html b/src/org/apache/http/entity/package.html
new file mode 100644
index 0000000..11d491e
--- /dev/null
+++ b/src/org/apache/http/entity/package.html
@@ -0,0 +1,58 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/entity/package.html $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Representations for HTTP message entities.
+
+An {@link org.apache.http.HttpEntity entity} is the optional content of a
+{@link org.apache.http.HttpMessage message}.
+You'll find a basic selection of entity implementations here.
+If you need to send an entity, you can provide it for example as a
+{@link org.apache.http.entity.ByteArrayEntity byte array},
+{@link org.apache.http.entity.StringEntity string},
+{@link org.apache.http.entity.FileEntity file}, or through an arbitrary
+{@link org.apache.http.entity.InputStreamEntity input stream}.
+If you receive a message with an entity, you typically get that as a
+{@link org.apache.http.entity.BasicHttpEntity basic} entity.
+Entity implementations can be
+{@link org.apache.http.entity.HttpEntityWrapper wrapped},
+for example to
+{@link org.apache.http.entity.BufferedHttpEntity buffer}
+the content in memory.
+
+
+
+</body>
+</html>
diff --git a/src/org/apache/http/impl/AbstractHttpClientConnection.java b/src/org/apache/http/impl/AbstractHttpClientConnection.java
new file mode 100644
index 0000000..ebfaabb
--- /dev/null
+++ b/src/org/apache/http/impl/AbstractHttpClientConnection.java
@@ -0,0 +1,212 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/AbstractHttpClientConnection.java $
+ * $Revision: 627457 $
+ * $Date: 2008-02-13 07:14:19 -0800 (Wed, 13 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.impl.entity.EntityDeserializer;
+import org.apache.http.impl.entity.EntitySerializer;
+import org.apache.http.impl.entity.LaxContentLengthStrategy;
+import org.apache.http.impl.entity.StrictContentLengthStrategy;
+import org.apache.http.impl.io.HttpRequestWriter;
+import org.apache.http.impl.io.HttpResponseParser;
+import org.apache.http.io.HttpMessageParser;
+import org.apache.http.io.HttpMessageWriter;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Abstract client-side HTTP connection capable of transmitting and receiving data
+ * using arbitrary {@link SessionInputBuffer} and {@link SessionOutputBuffer}
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 627457 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractHttpClientConnection implements HttpClientConnection {
+
+ private final EntitySerializer entityserializer;
+ private final EntityDeserializer entitydeserializer;
+
+ private SessionInputBuffer inbuffer = null;
+ private SessionOutputBuffer outbuffer = null;
+ private HttpMessageParser responseParser = null;
+ private HttpMessageWriter requestWriter = null;
+ private HttpConnectionMetricsImpl metrics = null;
+
+
+
+ public AbstractHttpClientConnection() {
+ super();
+ this.entityserializer = createEntitySerializer();
+ this.entitydeserializer = createEntityDeserializer();
+ }
+
+ protected abstract void assertOpen() throws IllegalStateException;
+
+ protected EntityDeserializer createEntityDeserializer() {
+ return new EntityDeserializer(new LaxContentLengthStrategy());
+ }
+
+ protected EntitySerializer createEntitySerializer() {
+ return new EntitySerializer(new StrictContentLengthStrategy());
+ }
+
+ protected HttpResponseFactory createHttpResponseFactory() {
+ return new DefaultHttpResponseFactory();
+ }
+
+ protected HttpMessageParser createResponseParser(
+ final SessionInputBuffer buffer,
+ final HttpResponseFactory responseFactory,
+ final HttpParams params) {
+ // override in derived class to specify a line parser
+ return new HttpResponseParser(buffer, null, responseFactory, params);
+ }
+
+ protected HttpMessageWriter createRequestWriter(
+ final SessionOutputBuffer buffer,
+ final HttpParams params) {
+ // override in derived class to specify a line formatter
+ return new HttpRequestWriter(buffer, null, params);
+ }
+
+ protected void init(
+ final SessionInputBuffer inbuffer,
+ final SessionOutputBuffer outbuffer,
+ final HttpParams params) {
+ if (inbuffer == null) {
+ throw new IllegalArgumentException("Input session buffer may not be null");
+ }
+ if (outbuffer == null) {
+ throw new IllegalArgumentException("Output session buffer may not be null");
+ }
+ this.inbuffer = inbuffer;
+ this.outbuffer = outbuffer;
+ this.responseParser = createResponseParser(
+ inbuffer,
+ createHttpResponseFactory(),
+ params);
+ this.requestWriter = createRequestWriter(
+ outbuffer, params);
+ this.metrics = new HttpConnectionMetricsImpl(
+ inbuffer.getMetrics(),
+ outbuffer.getMetrics());
+ }
+
+ public boolean isResponseAvailable(int timeout) throws IOException {
+ assertOpen();
+ return this.inbuffer.isDataAvailable(timeout);
+ }
+
+ public void sendRequestHeader(final HttpRequest request)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ assertOpen();
+ this.requestWriter.write(request);
+ this.metrics.incrementRequestCount();
+ }
+
+ public void sendRequestEntity(final HttpEntityEnclosingRequest request)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ assertOpen();
+ if (request.getEntity() == null) {
+ return;
+ }
+ this.entityserializer.serialize(
+ this.outbuffer,
+ request,
+ request.getEntity());
+ }
+
+ protected void doFlush() throws IOException {
+ this.outbuffer.flush();
+ }
+
+ public void flush() throws IOException {
+ assertOpen();
+ doFlush();
+ }
+
+ public HttpResponse receiveResponseHeader()
+ throws HttpException, IOException {
+ assertOpen();
+ HttpResponse response = (HttpResponse) this.responseParser.parse();
+ if (response.getStatusLine().getStatusCode() >= 200) {
+ this.metrics.incrementResponseCount();
+ }
+ return response;
+ }
+
+ public void receiveResponseEntity(final HttpResponse response)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ assertOpen();
+ HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, response);
+ response.setEntity(entity);
+ }
+
+ public boolean isStale() {
+ if (!isOpen()) {
+ return true;
+ }
+ try {
+ this.inbuffer.isDataAvailable(1);
+ return false;
+ } catch (IOException ex) {
+ return true;
+ }
+ }
+
+ public HttpConnectionMetrics getMetrics() {
+ return this.metrics;
+ }
+
+}
diff --git a/src/org/apache/http/impl/AbstractHttpServerConnection.java b/src/org/apache/http/impl/AbstractHttpServerConnection.java
new file mode 100644
index 0000000..ef68ed3
--- /dev/null
+++ b/src/org/apache/http/impl/AbstractHttpServerConnection.java
@@ -0,0 +1,202 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/AbstractHttpServerConnection.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestFactory;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpServerConnection;
+import org.apache.http.impl.entity.EntityDeserializer;
+import org.apache.http.impl.entity.EntitySerializer;
+import org.apache.http.impl.entity.LaxContentLengthStrategy;
+import org.apache.http.impl.entity.StrictContentLengthStrategy;
+import org.apache.http.impl.io.HttpRequestParser;
+import org.apache.http.impl.io.HttpResponseWriter;
+import org.apache.http.io.HttpMessageParser;
+import org.apache.http.io.HttpMessageWriter;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Abstract server-side HTTP connection capable of transmitting and receiving data
+ * using arbitrary {@link SessionInputBuffer} and {@link SessionOutputBuffer}
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractHttpServerConnection implements HttpServerConnection {
+
+ private final EntitySerializer entityserializer;
+ private final EntityDeserializer entitydeserializer;
+
+ private SessionInputBuffer inbuffer = null;
+ private SessionOutputBuffer outbuffer = null;
+ private HttpMessageParser requestParser = null;
+ private HttpMessageWriter responseWriter = null;
+ private HttpConnectionMetricsImpl metrics = null;
+
+
+
+ public AbstractHttpServerConnection() {
+ super();
+ this.entityserializer = createEntitySerializer();
+ this.entitydeserializer = createEntityDeserializer();
+ }
+
+ protected abstract void assertOpen() throws IllegalStateException;
+
+ protected EntityDeserializer createEntityDeserializer() {
+ return new EntityDeserializer(new LaxContentLengthStrategy());
+ }
+
+ protected EntitySerializer createEntitySerializer() {
+ return new EntitySerializer(new StrictContentLengthStrategy());
+ }
+
+ protected HttpRequestFactory createHttpRequestFactory() {
+ return new DefaultHttpRequestFactory();
+ }
+
+ protected HttpMessageParser createRequestParser(
+ final SessionInputBuffer buffer,
+ final HttpRequestFactory requestFactory,
+ final HttpParams params) {
+ // override in derived class to specify a line parser
+ return new HttpRequestParser(buffer, null, requestFactory, params);
+ }
+
+ protected HttpMessageWriter createResponseWriter(
+ final SessionOutputBuffer buffer,
+ final HttpParams params) {
+ // override in derived class to specify a line formatter
+ return new HttpResponseWriter(buffer, null, params);
+ }
+
+
+ protected void init(
+ final SessionInputBuffer inbuffer,
+ final SessionOutputBuffer outbuffer,
+ final HttpParams params) {
+ if (inbuffer == null) {
+ throw new IllegalArgumentException("Input session buffer may not be null");
+ }
+ if (outbuffer == null) {
+ throw new IllegalArgumentException("Output session buffer may not be null");
+ }
+ this.inbuffer = inbuffer;
+ this.outbuffer = outbuffer;
+ this.requestParser = createRequestParser(
+ inbuffer,
+ createHttpRequestFactory(),
+ params);
+ this.responseWriter = createResponseWriter(
+ outbuffer, params);
+ this.metrics = new HttpConnectionMetricsImpl(
+ inbuffer.getMetrics(),
+ outbuffer.getMetrics());
+ }
+
+ public HttpRequest receiveRequestHeader()
+ throws HttpException, IOException {
+ assertOpen();
+ HttpRequest request = (HttpRequest) this.requestParser.parse();
+ this.metrics.incrementRequestCount();
+ return request;
+ }
+
+ public void receiveRequestEntity(final HttpEntityEnclosingRequest request)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ assertOpen();
+ HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, request);
+ request.setEntity(entity);
+ }
+
+ protected void doFlush() throws IOException {
+ this.outbuffer.flush();
+ }
+
+ public void flush() throws IOException {
+ assertOpen();
+ doFlush();
+ }
+
+ public void sendResponseHeader(final HttpResponse response)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ assertOpen();
+ this.responseWriter.write(response);
+ if (response.getStatusLine().getStatusCode() >= 200) {
+ this.metrics.incrementResponseCount();
+ }
+ }
+
+ public void sendResponseEntity(final HttpResponse response)
+ throws HttpException, IOException {
+ if (response.getEntity() == null) {
+ return;
+ }
+ this.entityserializer.serialize(
+ this.outbuffer,
+ response,
+ response.getEntity());
+ }
+
+ public boolean isStale() {
+ assertOpen();
+ try {
+ this.inbuffer.isDataAvailable(1);
+ return false;
+ } catch (IOException ex) {
+ return true;
+ }
+ }
+
+ public HttpConnectionMetrics getMetrics() {
+ return this.metrics;
+ }
+
+}
diff --git a/src/org/apache/http/impl/DefaultConnectionReuseStrategy.java b/src/org/apache/http/impl/DefaultConnectionReuseStrategy.java
new file mode 100644
index 0000000..da1d5fd
--- /dev/null
+++ b/src/org/apache/http/impl/DefaultConnectionReuseStrategy.java
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/DefaultConnectionReuseStrategy.java $
+ * $Revision: 602537 $
+ * $Date: 2007-12-08 11:42:06 -0800 (Sat, 08 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpConnection;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.ParseException;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.TokenIterator;
+import org.apache.http.message.BasicTokenIterator;
+
+/**
+ * Default implementation of a strategy deciding about connection re-use.
+ * The default implementation first checks some basics, for example
+ * whether the connection is still open or whether the end of the
+ * request entity can be determined without closing the connection.
+ * If these checks pass, the tokens in the "Connection" header will
+ * be examined. In the absence of a "Connection" header, the
+ * non-standard but commonly used "Proxy-Connection" header takes
+ * it's role. A token "close" indicates that the connection cannot
+ * be reused. If there is no such token, a token "keep-alive" indicates
+ * that the connection should be re-used. If neither token is found,
+ * or if there are no "Connection" headers, the default policy for
+ * the HTTP version is applied. Since HTTP/1.1, connections are re-used
+ * by default. Up until HTTP/1.0, connections are not re-used by default.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 602537 $
+ *
+ * @since 4.0
+ */
+public class DefaultConnectionReuseStrategy
+ implements ConnectionReuseStrategy {
+
+ public DefaultConnectionReuseStrategy() {
+ super();
+ }
+
+ // see interface ConnectionReuseStrategy
+ public boolean keepAlive(final HttpResponse response,
+ final HttpContext context) {
+ if (response == null) {
+ throw new IllegalArgumentException
+ ("HTTP response may not be null.");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException
+ ("HTTP context may not be null.");
+ }
+
+ HttpConnection conn = (HttpConnection)
+ context.getAttribute(ExecutionContext.HTTP_CONNECTION);
+
+ if (conn != null && !conn.isOpen())
+ return false;
+ // do NOT check for stale connection, that is an expensive operation
+
+ // Check for a self-terminating entity. If the end of the entity will
+ // be indicated by closing the connection, there is no keep-alive.
+ HttpEntity entity = response.getEntity();
+ ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
+ if (entity != null) {
+ if (entity.getContentLength() < 0) {
+ if (!entity.isChunked() ||
+ ver.lessEquals(HttpVersion.HTTP_1_0)) {
+ // if the content length is not known and is not chunk
+ // encoded, the connection cannot be reused
+ return false;
+ }
+ }
+ }
+
+ // Check for the "Connection" header. If that is absent, check for
+ // the "Proxy-Connection" header. The latter is an unspecified and
+ // broken but unfortunately common extension of HTTP.
+ HeaderIterator hit = response.headerIterator(HTTP.CONN_DIRECTIVE);
+ if (!hit.hasNext())
+ hit = response.headerIterator("Proxy-Connection");
+
+ // Experimental usage of the "Connection" header in HTTP/1.0 is
+ // documented in RFC 2068, section 19.7.1. A token "keep-alive" is
+ // used to indicate that the connection should be persistent.
+ // Note that the final specification of HTTP/1.1 in RFC 2616 does not
+ // include this information. Neither is the "Connection" header
+ // mentioned in RFC 1945, which informally describes HTTP/1.0.
+ //
+ // RFC 2616 specifies "close" as the only connection token with a
+ // specific meaning: it disables persistent connections.
+ //
+ // The "Proxy-Connection" header is not formally specified anywhere,
+ // but is commonly used to carry one token, "close" or "keep-alive".
+ // The "Connection" header, on the other hand, is defined as a
+ // sequence of tokens, where each token is a header name, and the
+ // token "close" has the above-mentioned additional meaning.
+ //
+ // To get through this mess, we treat the "Proxy-Connection" header
+ // in exactly the same way as the "Connection" header, but only if
+ // the latter is missing. We scan the sequence of tokens for both
+ // "close" and "keep-alive". As "close" is specified by RFC 2068,
+ // it takes precedence and indicates a non-persistent connection.
+ // If there is no "close" but a "keep-alive", we take the hint.
+
+ if (hit.hasNext()) {
+ try {
+ TokenIterator ti = createTokenIterator(hit);
+ boolean keepalive = false;
+ while (ti.hasNext()) {
+ final String token = ti.nextToken();
+ if (HTTP.CONN_CLOSE.equalsIgnoreCase(token)) {
+ return false;
+ } else if (HTTP.CONN_KEEP_ALIVE.equalsIgnoreCase(token)) {
+ // continue the loop, there may be a "close" afterwards
+ keepalive = true;
+ }
+ }
+ if (keepalive)
+ return true;
+ // neither "close" nor "keep-alive", use default policy
+
+ } catch (ParseException px) {
+ // invalid connection header means no persistent connection
+ // we don't have logging in HttpCore, so the exception is lost
+ return false;
+ }
+ }
+
+ // default since HTTP/1.1 is persistent, before it was non-persistent
+ return !ver.lessEquals(HttpVersion.HTTP_1_0);
+ }
+
+
+ /**
+ * Creates a token iterator from a header iterator.
+ * This method can be overridden to replace the implementation of
+ * the token iterator.
+ *
+ * @param hit the header iterator
+ *
+ * @return the token iterator
+ */
+ protected TokenIterator createTokenIterator(HeaderIterator hit) {
+ return new BasicTokenIterator(hit);
+ }
+}
diff --git a/src/org/apache/http/impl/DefaultHttpClientConnection.java b/src/org/apache/http/impl/DefaultHttpClientConnection.java
new file mode 100644
index 0000000..c0a96f5
--- /dev/null
+++ b/src/org/apache/http/impl/DefaultHttpClientConnection.java
@@ -0,0 +1,87 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/DefaultHttpClientConnection.java $
+ * $Revision: 561083 $
+ * $Date: 2007-07-30 11:31:17 -0700 (Mon, 30 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Default implementation of a client-side HTTP connection.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 561083 $
+ *
+ * @since 4.0
+ */
+public class DefaultHttpClientConnection extends SocketHttpClientConnection {
+
+ public DefaultHttpClientConnection() {
+ super();
+ }
+
+ public void bind(
+ final Socket socket,
+ final HttpParams params) throws IOException {
+ if (socket == null) {
+ throw new IllegalArgumentException("Socket may not be null");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ assertNotOpen();
+ socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
+ socket.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
+
+ int linger = HttpConnectionParams.getLinger(params);
+ if (linger >= 0) {
+ socket.setSoLinger(linger > 0, linger);
+ }
+ super.bind(socket, params);
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("[");
+ if (isOpen()) {
+ buffer.append(getRemotePort());
+ } else {
+ buffer.append("closed");
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/impl/DefaultHttpRequestFactory.java b/src/org/apache/http/impl/DefaultHttpRequestFactory.java
new file mode 100644
index 0000000..dee36c9
--- /dev/null
+++ b/src/org/apache/http/impl/DefaultHttpRequestFactory.java
@@ -0,0 +1,113 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/DefaultHttpRequestFactory.java $
+ * $Revision: 618367 $
+ * $Date: 2008-02-04 10:26:06 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestFactory;
+import org.apache.http.MethodNotSupportedException;
+import org.apache.http.RequestLine;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicHttpRequest;
+
+/**
+ * Default implementation of a factory for creating request objects.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618367 $
+ *
+ * @since 4.0
+ */
+public class DefaultHttpRequestFactory implements HttpRequestFactory {
+
+ private static final String[] RFC2616_COMMON_METHODS = {
+ "GET"
+ };
+
+ private static final String[] RFC2616_ENTITY_ENC_METHODS = {
+ "POST",
+ "PUT"
+ };
+
+ private static final String[] RFC2616_SPECIAL_METHODS = {
+ "HEAD",
+ "OPTIONS",
+ "DELETE",
+ "TRACE"
+ };
+
+
+ public DefaultHttpRequestFactory() {
+ super();
+ }
+
+ private static boolean isOneOf(final String[] methods, final String method) {
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].equalsIgnoreCase(method)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public HttpRequest newHttpRequest(final RequestLine requestline)
+ throws MethodNotSupportedException {
+ if (requestline == null) {
+ throw new IllegalArgumentException("Request line may not be null");
+ }
+ String method = requestline.getMethod();
+ if (isOneOf(RFC2616_COMMON_METHODS, method)) {
+ return new BasicHttpRequest(requestline);
+ } else if (isOneOf(RFC2616_ENTITY_ENC_METHODS, method)) {
+ return new BasicHttpEntityEnclosingRequest(requestline);
+ } else if (isOneOf(RFC2616_SPECIAL_METHODS, method)) {
+ return new BasicHttpRequest(requestline);
+ } else {
+ throw new MethodNotSupportedException(method + " method not supported");
+ }
+ }
+
+ public HttpRequest newHttpRequest(final String method, final String uri)
+ throws MethodNotSupportedException {
+ if (isOneOf(RFC2616_COMMON_METHODS, method)) {
+ return new BasicHttpRequest(method, uri);
+ } else if (isOneOf(RFC2616_ENTITY_ENC_METHODS, method)) {
+ return new BasicHttpEntityEnclosingRequest(method, uri);
+ } else if (isOneOf(RFC2616_SPECIAL_METHODS, method)) {
+ return new BasicHttpRequest(method, uri);
+ } else {
+ throw new MethodNotSupportedException(method
+ + " method not supported");
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/DefaultHttpResponseFactory.java b/src/org/apache/http/impl/DefaultHttpResponseFactory.java
new file mode 100644
index 0000000..40a2c9a
--- /dev/null
+++ b/src/org/apache/http/impl/DefaultHttpResponseFactory.java
@@ -0,0 +1,121 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/DefaultHttpResponseFactory.java $
+ * $Revision: 618367 $
+ * $Date: 2008-02-04 10:26:06 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.util.Locale;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.message.BasicStatusLine;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.ReasonPhraseCatalog;
+import org.apache.http.impl.EnglishReasonPhraseCatalog;
+
+/**
+ * Default implementation of a factory for creating response objects.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618367 $
+ *
+ * @since 4.0
+ */
+public class DefaultHttpResponseFactory implements HttpResponseFactory {
+
+ /** The catalog for looking up reason phrases. */
+ protected final ReasonPhraseCatalog reasonCatalog;
+
+
+ /**
+ * Creates a new response factory with the given catalog.
+ *
+ * @param catalog the catalog of reason phrases
+ */
+ public DefaultHttpResponseFactory(ReasonPhraseCatalog catalog) {
+ if (catalog == null) {
+ throw new IllegalArgumentException
+ ("Reason phrase catalog must not be null.");
+ }
+ this.reasonCatalog = catalog;
+ }
+
+ /**
+ * Creates a new response factory with the default catalog.
+ * The default catalog is
+ * {@link EnglishReasonPhraseCatalog EnglishReasonPhraseCatalog}.
+ */
+ public DefaultHttpResponseFactory() {
+ this(EnglishReasonPhraseCatalog.INSTANCE);
+ }
+
+
+ // non-javadoc, see interface HttpResponseFactory
+ public HttpResponse newHttpResponse(final ProtocolVersion ver,
+ final int status,
+ HttpContext context) {
+ if (ver == null) {
+ throw new IllegalArgumentException("HTTP version may not be null");
+ }
+ final Locale loc = determineLocale(context);
+ final String reason = reasonCatalog.getReason(status, loc);
+ StatusLine statusline = new BasicStatusLine(ver, status, reason);
+ return new BasicHttpResponse(statusline, reasonCatalog, loc);
+ }
+
+
+ // non-javadoc, see interface HttpResponseFactory
+ public HttpResponse newHttpResponse(final StatusLine statusline,
+ HttpContext context) {
+ if (statusline == null) {
+ throw new IllegalArgumentException("Status line may not be null");
+ }
+ final Locale loc = determineLocale(context);
+ return new BasicHttpResponse(statusline, reasonCatalog, loc);
+ }
+
+
+ /**
+ * Determines the locale of the response.
+ * The implementation in this class always returns the default locale.
+ *
+ * @param context the context from which to determine the locale, or
+ * <code>null</code> to use the default locale
+ *
+ * @return the locale for the response, never <code>null</code>
+ */
+ protected Locale determineLocale(HttpContext context) {
+ return Locale.getDefault();
+ }
+}
diff --git a/src/org/apache/http/impl/DefaultHttpServerConnection.java b/src/org/apache/http/impl/DefaultHttpServerConnection.java
new file mode 100644
index 0000000..d296fc8
--- /dev/null
+++ b/src/org/apache/http/impl/DefaultHttpServerConnection.java
@@ -0,0 +1,85 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/DefaultHttpServerConnection.java $
+ * $Revision: 561083 $
+ * $Date: 2007-07-30 11:31:17 -0700 (Mon, 30 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Default implementation of a server-side HTTP connection.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 561083 $
+ *
+ * @since 4.0
+ */
+public class DefaultHttpServerConnection extends SocketHttpServerConnection {
+
+ public DefaultHttpServerConnection() {
+ super();
+ }
+
+ public void bind(final Socket socket, final HttpParams params) throws IOException {
+ if (socket == null) {
+ throw new IllegalArgumentException("Socket may not be null");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ assertNotOpen();
+ socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
+ socket.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
+
+ int linger = HttpConnectionParams.getLinger(params);
+ if (linger >= 0) {
+ socket.setSoLinger(linger > 0, linger);
+ }
+ super.bind(socket, params);
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("[");
+ if (isOpen()) {
+ buffer.append(getRemotePort());
+ } else {
+ buffer.append("closed");
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/impl/EnglishReasonPhraseCatalog.java b/src/org/apache/http/impl/EnglishReasonPhraseCatalog.java
new file mode 100644
index 0000000..f1aeee1
--- /dev/null
+++ b/src/org/apache/http/impl/EnglishReasonPhraseCatalog.java
@@ -0,0 +1,234 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/EnglishReasonPhraseCatalog.java $
+ * $Revision: 505744 $
+ * $Date: 2007-02-10 10:58:45 -0800 (Sat, 10 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.util.Locale;
+
+import org.apache.http.HttpStatus;
+import org.apache.http.ReasonPhraseCatalog;
+
+
+/**
+ * English reason phrases for HTTP status codes.
+ * All status codes defined in RFC1945 (HTTP/1.0), RFC2616 (HTTP/1.1), and
+ * RFC2518 (WebDAV) are supported.
+ *
+ * @author Unascribed
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ *
+ * @version $Revision: 505744 $
+ */
+public class EnglishReasonPhraseCatalog
+ implements ReasonPhraseCatalog {
+
+ // static array with english reason phrases defined below
+
+ /**
+ * The default instance of this catalog.
+ * This catalog is thread safe, so there typically
+ * is no need to create other instances.
+ */
+ public final static EnglishReasonPhraseCatalog INSTANCE =
+ new EnglishReasonPhraseCatalog();
+
+
+ /**
+ * Restricted default constructor, for derived classes.
+ * If you need an instance of this class, use {@link #INSTANCE INSTANCE}.
+ */
+ protected EnglishReasonPhraseCatalog() {
+ // no body
+ }
+
+
+ /**
+ * Obtains the reason phrase for a status code.
+ *
+ * @param status the status code, in the range 100-599
+ * @param loc ignored
+ *
+ * @return the reason phrase, or <code>null</code>
+ */
+ public String getReason(int status, Locale loc) {
+ if ((status < 100) || (status >= 600)) {
+ throw new IllegalArgumentException
+ ("Unknown category for status code " + status + ".");
+ }
+
+ final int category = status / 100;
+ final int subcode = status - 100*category;
+
+ String reason = null;
+ if (REASON_PHRASES[category].length > subcode)
+ reason = REASON_PHRASES[category][subcode];
+
+ return reason;
+ }
+
+
+ /** Reason phrases lookup table. */
+ private static final String[][] REASON_PHRASES = new String[][]{
+ null,
+ new String[3], // 1xx
+ new String[8], // 2xx
+ new String[8], // 3xx
+ new String[25], // 4xx
+ new String[8] // 5xx
+ };
+
+
+
+ /**
+ * Stores the given reason phrase, by status code.
+ * Helper method to initialize the static lookup table.
+ *
+ * @param status the status code for which to define the phrase
+ * @param reason the reason phrase for this status code
+ */
+ private static void setReason(int status, String reason) {
+ final int category = status / 100;
+ final int subcode = status - 100*category;
+ REASON_PHRASES[category][subcode] = reason;
+ }
+
+
+ // ----------------------------------------------------- Static Initializer
+
+ /** Set up status code to "reason phrase" map. */
+ static {
+ // HTTP 1.0 Server status codes -- see RFC 1945
+ setReason(HttpStatus.SC_OK,
+ "OK");
+ setReason(HttpStatus.SC_CREATED,
+ "Created");
+ setReason(HttpStatus.SC_ACCEPTED,
+ "Accepted");
+ setReason(HttpStatus.SC_NO_CONTENT,
+ "No Content");
+ setReason(HttpStatus.SC_MOVED_PERMANENTLY,
+ "Moved Permanently");
+ setReason(HttpStatus.SC_MOVED_TEMPORARILY,
+ "Moved Temporarily");
+ setReason(HttpStatus.SC_NOT_MODIFIED,
+ "Not Modified");
+ setReason(HttpStatus.SC_BAD_REQUEST,
+ "Bad Request");
+ setReason(HttpStatus.SC_UNAUTHORIZED,
+ "Unauthorized");
+ setReason(HttpStatus.SC_FORBIDDEN,
+ "Forbidden");
+ setReason(HttpStatus.SC_NOT_FOUND,
+ "Not Found");
+ setReason(HttpStatus.SC_INTERNAL_SERVER_ERROR,
+ "Internal Server Error");
+ setReason(HttpStatus.SC_NOT_IMPLEMENTED,
+ "Not Implemented");
+ setReason(HttpStatus.SC_BAD_GATEWAY,
+ "Bad Gateway");
+ setReason(HttpStatus.SC_SERVICE_UNAVAILABLE,
+ "Service Unavailable");
+
+ // HTTP 1.1 Server status codes -- see RFC 2048
+ setReason(HttpStatus.SC_CONTINUE,
+ "Continue");
+ setReason(HttpStatus.SC_TEMPORARY_REDIRECT,
+ "Temporary Redirect");
+ setReason(HttpStatus.SC_METHOD_NOT_ALLOWED,
+ "Method Not Allowed");
+ setReason(HttpStatus.SC_CONFLICT,
+ "Conflict");
+ setReason(HttpStatus.SC_PRECONDITION_FAILED,
+ "Precondition Failed");
+ setReason(HttpStatus.SC_REQUEST_TOO_LONG,
+ "Request Too Long");
+ setReason(HttpStatus.SC_REQUEST_URI_TOO_LONG,
+ "Request-URI Too Long");
+ setReason(HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE,
+ "Unsupported Media Type");
+ setReason(HttpStatus.SC_MULTIPLE_CHOICES,
+ "Multiple Choices");
+ setReason(HttpStatus.SC_SEE_OTHER,
+ "See Other");
+ setReason(HttpStatus.SC_USE_PROXY,
+ "Use Proxy");
+ setReason(HttpStatus.SC_PAYMENT_REQUIRED,
+ "Payment Required");
+ setReason(HttpStatus.SC_NOT_ACCEPTABLE,
+ "Not Acceptable");
+ setReason(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED,
+ "Proxy Authentication Required");
+ setReason(HttpStatus.SC_REQUEST_TIMEOUT,
+ "Request Timeout");
+
+ setReason(HttpStatus.SC_SWITCHING_PROTOCOLS,
+ "Switching Protocols");
+ setReason(HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION,
+ "Non Authoritative Information");
+ setReason(HttpStatus.SC_RESET_CONTENT,
+ "Reset Content");
+ setReason(HttpStatus.SC_PARTIAL_CONTENT,
+ "Partial Content");
+ setReason(HttpStatus.SC_GATEWAY_TIMEOUT,
+ "Gateway Timeout");
+ setReason(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED,
+ "Http Version Not Supported");
+ setReason(HttpStatus.SC_GONE,
+ "Gone");
+ setReason(HttpStatus.SC_LENGTH_REQUIRED,
+ "Length Required");
+ setReason(HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE,
+ "Requested Range Not Satisfiable");
+ setReason(HttpStatus.SC_EXPECTATION_FAILED,
+ "Expectation Failed");
+
+ // WebDAV Server-specific status codes
+ setReason(HttpStatus.SC_PROCESSING,
+ "Processing");
+ setReason(HttpStatus.SC_MULTI_STATUS,
+ "Multi-Status");
+ setReason(HttpStatus.SC_UNPROCESSABLE_ENTITY,
+ "Unprocessable Entity");
+ setReason(HttpStatus.SC_INSUFFICIENT_SPACE_ON_RESOURCE,
+ "Insufficient Space On Resource");
+ setReason(HttpStatus.SC_METHOD_FAILURE,
+ "Method Failure");
+ setReason(HttpStatus.SC_LOCKED,
+ "Locked");
+ setReason(HttpStatus.SC_INSUFFICIENT_STORAGE,
+ "Insufficient Storage");
+ setReason(HttpStatus.SC_FAILED_DEPENDENCY,
+ "Failed Dependency");
+ }
+
+
+}
diff --git a/src/org/apache/http/impl/HttpConnectionMetricsImpl.java b/src/org/apache/http/impl/HttpConnectionMetricsImpl.java
new file mode 100644
index 0000000..4f4eacf
--- /dev/null
+++ b/src/org/apache/http/impl/HttpConnectionMetricsImpl.java
@@ -0,0 +1,146 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/HttpConnectionMetricsImpl.java $
+ * $Revision: 548031 $
+ * $Date: 2007-06-17 04:28:38 -0700 (Sun, 17 Jun 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.util.HashMap;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.io.HttpTransportMetrics;
+
+/**
+ * Implementation of the metrics interface.
+ */
+public class HttpConnectionMetricsImpl implements HttpConnectionMetrics {
+
+ public static final String REQUEST_COUNT = "http.request-count";
+ public static final String RESPONSE_COUNT = "http.response-count";
+ public static final String SENT_BYTES_COUNT = "http.sent-bytes-count";
+ public static final String RECEIVED_BYTES_COUNT = "http.received-bytes-count";
+
+ private final HttpTransportMetrics inTransportMetric;
+ private final HttpTransportMetrics outTransportMetric;
+ private long requestCount = 0;
+ private long responseCount = 0;
+
+ /**
+ * The cache map for all metrics values.
+ */
+ private HashMap metricsCache;
+
+ public HttpConnectionMetricsImpl(
+ final HttpTransportMetrics inTransportMetric,
+ final HttpTransportMetrics outTransportMetric) {
+ super();
+ this.inTransportMetric = inTransportMetric;
+ this.outTransportMetric = outTransportMetric;
+ }
+
+ /* ------------------ Public interface method -------------------------- */
+
+ public long getReceivedBytesCount() {
+ if (this.inTransportMetric != null) {
+ return this.inTransportMetric.getBytesTransferred();
+ } else {
+ return -1;
+ }
+ }
+
+ public long getSentBytesCount() {
+ if (this.outTransportMetric != null) {
+ return this.outTransportMetric.getBytesTransferred();
+ } else {
+ return -1;
+ }
+ }
+
+ public long getRequestCount() {
+ return this.requestCount;
+ }
+
+ public void incrementRequestCount() {
+ this.requestCount++;
+ }
+
+ public long getResponseCount() {
+ return this.responseCount;
+ }
+
+ public void incrementResponseCount() {
+ this.responseCount++;
+ }
+
+ public Object getMetric(final String metricName) {
+ Object value = null;
+ if (this.metricsCache != null) {
+ value = this.metricsCache.get(metricName);
+ }
+ if (value == null) {
+ if (REQUEST_COUNT.equals(metricName)) {
+ value = new Long(requestCount);
+ } else if (RESPONSE_COUNT.equals(metricName)) {
+ value = new Long(responseCount);
+ } else if (RECEIVED_BYTES_COUNT.equals(metricName)) {
+ if (this.inTransportMetric != null) {
+ return new Long(this.inTransportMetric.getBytesTransferred());
+ } else {
+ return null;
+ }
+ } else if (SENT_BYTES_COUNT.equals(metricName)) {
+ if (this.outTransportMetric != null) {
+ return new Long(this.outTransportMetric.getBytesTransferred());
+ } else {
+ return null;
+ }
+ }
+ }
+ return value;
+ }
+
+ public void setMetric(final String metricName, Object obj) {
+ if (this.metricsCache == null) {
+ this.metricsCache = new HashMap();
+ }
+ this.metricsCache.put(metricName, obj);
+ }
+
+ public void reset() {
+ if (this.outTransportMetric != null) {
+ this.outTransportMetric.reset();
+ }
+ if (this.inTransportMetric != null) {
+ this.inTransportMetric.reset();
+ }
+ this.requestCount = 0;
+ this.responseCount = 0;
+ this.metricsCache = null;
+ }
+
+}
diff --git a/src/org/apache/http/impl/NoConnectionReuseStrategy.java b/src/org/apache/http/impl/NoConnectionReuseStrategy.java
new file mode 100644
index 0000000..c7a5f73
--- /dev/null
+++ b/src/org/apache/http/impl/NoConnectionReuseStrategy.java
@@ -0,0 +1,65 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/NoConnectionReuseStrategy.java $
+ * $Revision: 502684 $
+ * $Date: 2007-02-02 10:25:38 -0800 (Fri, 02 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpResponse;
+import org.apache.http.protocol.HttpContext;
+
+
+/**
+ * A strategy that never re-uses a connection.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 502684 $
+ *
+ * @since 4.0
+ */
+public class NoConnectionReuseStrategy implements ConnectionReuseStrategy {
+
+ // default constructor
+
+
+ // non-JavaDoc, see interface ConnectionReuseStrategy
+ public boolean keepAlive(final HttpResponse response, final HttpContext context) {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/org/apache/http/impl/SocketHttpClientConnection.java b/src/org/apache/http/impl/SocketHttpClientConnection.java
new file mode 100644
index 0000000..1e551e0
--- /dev/null
+++ b/src/org/apache/http/impl/SocketHttpClientConnection.java
@@ -0,0 +1,208 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/SocketHttpClientConnection.java $
+ * $Revision: 561083 $
+ * $Date: 2007-07-30 11:31:17 -0700 (Mon, 30 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.http.HttpInetConnection;
+import org.apache.http.impl.io.SocketInputBuffer;
+import org.apache.http.impl.io.SocketOutputBuffer;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Implementation of a client-side HTTP connection that can be bound to a
+ * network Socket in order to receive and transmit data.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 561083 $
+ *
+ * @since 4.0
+ */
+public class SocketHttpClientConnection
+ extends AbstractHttpClientConnection implements HttpInetConnection {
+
+ private volatile boolean open;
+ private Socket socket = null;
+
+ public SocketHttpClientConnection() {
+ super();
+ }
+
+ protected void assertNotOpen() {
+ if (this.open) {
+ throw new IllegalStateException("Connection is already open");
+ }
+ }
+
+ protected void assertOpen() {
+ if (!this.open) {
+ throw new IllegalStateException("Connection is not open");
+ }
+ }
+
+ protected SessionInputBuffer createSessionInputBuffer(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ return new SocketInputBuffer(socket, buffersize, params);
+ }
+
+ protected SessionOutputBuffer createSessionOutputBuffer(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ return new SocketOutputBuffer(socket, buffersize, params);
+ }
+
+ protected void bind(
+ final Socket socket,
+ final HttpParams params) throws IOException {
+ if (socket == null) {
+ throw new IllegalArgumentException("Socket may not be null");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.socket = socket;
+
+ int buffersize = HttpConnectionParams.getSocketBufferSize(params);
+
+ init(
+ createSessionInputBuffer(socket, buffersize, params),
+ createSessionOutputBuffer(socket, buffersize, params),
+ params);
+
+ this.open = true;
+ }
+
+ public boolean isOpen() {
+ return this.open;
+ }
+
+ protected Socket getSocket() {
+ return this.socket;
+ }
+
+ public InetAddress getLocalAddress() {
+ if (this.socket != null) {
+ return this.socket.getLocalAddress();
+ } else {
+ return null;
+ }
+ }
+
+ public int getLocalPort() {
+ if (this.socket != null) {
+ return this.socket.getLocalPort();
+ } else {
+ return -1;
+ }
+ }
+
+ public InetAddress getRemoteAddress() {
+ if (this.socket != null) {
+ return this.socket.getInetAddress();
+ } else {
+ return null;
+ }
+ }
+
+ public int getRemotePort() {
+ if (this.socket != null) {
+ return this.socket.getPort();
+ } else {
+ return -1;
+ }
+ }
+
+ public void setSocketTimeout(int timeout) {
+ assertOpen();
+ if (this.socket != null) {
+ try {
+ this.socket.setSoTimeout(timeout);
+ } catch (SocketException ignore) {
+ // It is not quite clear from the Sun's documentation if there are any
+ // other legitimate cases for a socket exception to be thrown when setting
+ // SO_TIMEOUT besides the socket being already closed
+ }
+ }
+ }
+
+ public int getSocketTimeout() {
+ if (this.socket != null) {
+ try {
+ return this.socket.getSoTimeout();
+ } catch (SocketException ignore) {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ public void shutdown() throws IOException {
+ this.open = false;
+ Socket tmpsocket = this.socket;
+ if (tmpsocket != null) {
+ tmpsocket.close();
+ }
+ }
+
+ public void close() throws IOException {
+ if (!this.open) {
+ return;
+ }
+ this.open = false;
+ doFlush();
+ try {
+ try {
+ this.socket.shutdownOutput();
+ } catch (IOException ignore) {
+ }
+ try {
+ this.socket.shutdownInput();
+ } catch (IOException ignore) {
+ }
+ } catch (UnsupportedOperationException ignore) {
+ // if one isn't supported, the other one isn't either
+ }
+ this.socket.close();
+ }
+
+}
diff --git a/src/org/apache/http/impl/SocketHttpServerConnection.java b/src/org/apache/http/impl/SocketHttpServerConnection.java
new file mode 100644
index 0000000..cfa2bf9
--- /dev/null
+++ b/src/org/apache/http/impl/SocketHttpServerConnection.java
@@ -0,0 +1,202 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/SocketHttpServerConnection.java $
+ * $Revision: 561083 $
+ * $Date: 2007-07-30 11:31:17 -0700 (Mon, 30 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.http.HttpInetConnection;
+import org.apache.http.impl.io.SocketInputBuffer;
+import org.apache.http.impl.io.SocketOutputBuffer;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Implementation of a server-side HTTP connection that can be bound to a
+ * network Socket in order to receive and transmit data.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 561083 $
+ *
+ * @since 4.0
+ */
+public class SocketHttpServerConnection extends
+ AbstractHttpServerConnection implements HttpInetConnection {
+
+ private volatile boolean open;
+ private Socket socket = null;
+
+ public SocketHttpServerConnection() {
+ super();
+ }
+
+ protected void assertNotOpen() {
+ if (this.open) {
+ throw new IllegalStateException("Connection is already open");
+ }
+ }
+
+ protected void assertOpen() {
+ if (!this.open) {
+ throw new IllegalStateException("Connection is not open");
+ }
+ }
+
+ protected SessionInputBuffer createHttpDataReceiver(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ return new SocketInputBuffer(socket, buffersize, params);
+ }
+
+ protected SessionOutputBuffer createHttpDataTransmitter(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ return new SocketOutputBuffer(socket, buffersize, params);
+ }
+
+ protected void bind(final Socket socket, final HttpParams params) throws IOException {
+ if (socket == null) {
+ throw new IllegalArgumentException("Socket may not be null");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.socket = socket;
+
+ int buffersize = HttpConnectionParams.getSocketBufferSize(params);
+
+ init(
+ createHttpDataReceiver(socket, buffersize, params),
+ createHttpDataTransmitter(socket, buffersize, params),
+ params);
+
+ this.open = true;
+ }
+
+ protected Socket getSocket() {
+ return this.socket;
+ }
+
+ public boolean isOpen() {
+ return this.open;
+ }
+
+ public InetAddress getLocalAddress() {
+ if (this.socket != null) {
+ return this.socket.getLocalAddress();
+ } else {
+ return null;
+ }
+ }
+
+ public int getLocalPort() {
+ if (this.socket != null) {
+ return this.socket.getLocalPort();
+ } else {
+ return -1;
+ }
+ }
+
+ public InetAddress getRemoteAddress() {
+ if (this.socket != null) {
+ return this.socket.getInetAddress();
+ } else {
+ return null;
+ }
+ }
+
+ public int getRemotePort() {
+ if (this.socket != null) {
+ return this.socket.getPort();
+ } else {
+ return -1;
+ }
+ }
+
+ public void setSocketTimeout(int timeout) {
+ assertOpen();
+ if (this.socket != null) {
+ try {
+ this.socket.setSoTimeout(timeout);
+ } catch (SocketException ignore) {
+ // It is not quite clear from the Sun's documentation if there are any
+ // other legitimate cases for a socket exception to be thrown when setting
+ // SO_TIMEOUT besides the socket being already closed
+ }
+ }
+ }
+
+ public int getSocketTimeout() {
+ if (this.socket != null) {
+ try {
+ return this.socket.getSoTimeout();
+ } catch (SocketException ignore) {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ public void shutdown() throws IOException {
+ this.open = false;
+ Socket tmpsocket = this.socket;
+ if (tmpsocket != null) {
+ tmpsocket.close();
+ }
+ }
+
+ public void close() throws IOException {
+ if (!this.open) {
+ return;
+ }
+ this.open = false;
+ doFlush();
+ try {
+ this.socket.shutdownOutput();
+ } catch (IOException ignore) {
+ }
+ try {
+ this.socket.shutdownInput();
+ } catch (IOException ignore) {
+ }
+ this.socket.close();
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/AuthSchemeBase.java b/src/org/apache/http/impl/auth/AuthSchemeBase.java
new file mode 100644
index 0000000..689ce5d
--- /dev/null
+++ b/src/org/apache/http/impl/auth/AuthSchemeBase.java
@@ -0,0 +1,128 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/AuthSchemeBase.java $
+ * $Revision: 653867 $
+ * $Date: 2008-05-06 11:17:29 -0700 (Tue, 06 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Abstract authentication scheme class that serves as a basis
+ * for all authentication schemes supported by HttpClient. This class
+ * defines the generic way of parsing an authentication challenge. It
+ * does not make any assumptions regarding the format of the challenge
+ * nor does it impose any specific way of responding to that challenge.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+*/
+public abstract class AuthSchemeBase implements AuthScheme {
+
+ /**
+ * Flag whether authenticating against a proxy.
+ */
+ private boolean proxy;
+
+ public AuthSchemeBase() {
+ super();
+ }
+
+ /**
+ * Processes the given challenge token. Some authentication schemes
+ * may involve multiple challenge-response exchanges. Such schemes must be able
+ * to maintain the state information when dealing with sequential challenges
+ *
+ * @param header the challenge header
+ *
+ * @throws MalformedChallengeException is thrown if the authentication challenge
+ * is malformed
+ */
+ public void processChallenge(final Header header) throws MalformedChallengeException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ String authheader = header.getName();
+ if (authheader.equalsIgnoreCase(AUTH.WWW_AUTH)) {
+ this.proxy = false;
+ } else if (authheader.equalsIgnoreCase(AUTH.PROXY_AUTH)) {
+ this.proxy = true;
+ } else {
+ throw new MalformedChallengeException("Unexpected header name: " + authheader);
+ }
+
+ CharArrayBuffer buffer;
+ int pos;
+ if (header instanceof FormattedHeader) {
+ buffer = ((FormattedHeader) header).getBuffer();
+ pos = ((FormattedHeader) header).getValuePos();
+ } else {
+ String s = header.getValue();
+ if (s == null) {
+ throw new MalformedChallengeException("Header value is null");
+ }
+ buffer = new CharArrayBuffer(s.length());
+ buffer.append(s);
+ pos = 0;
+ }
+ while (pos < buffer.length() && HTTP.isWhitespace(buffer.charAt(pos))) {
+ pos++;
+ }
+ int beginIndex = pos;
+ while (pos < buffer.length() && !HTTP.isWhitespace(buffer.charAt(pos))) {
+ pos++;
+ }
+ int endIndex = pos;
+ String s = buffer.substring(beginIndex, endIndex);
+ if (!s.equalsIgnoreCase(getSchemeName())) {
+ throw new MalformedChallengeException("Invalid scheme identifier: " + s);
+ }
+
+ parseChallenge(buffer, pos, buffer.length());
+ }
+
+ protected abstract void parseChallenge(
+ CharArrayBuffer buffer, int pos, int len) throws MalformedChallengeException;
+
+ /**
+ * Returns <code>true</code> if authenticating against a proxy, <code>false</code>
+ * otherwise.
+ *
+ * @return <code>true</code> if authenticating against a proxy, <code>false</code>
+ * otherwise
+ */
+ public boolean isProxy() {
+ return this.proxy;
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/BasicScheme.java b/src/org/apache/http/impl/auth/BasicScheme.java
new file mode 100644
index 0000000..88ea110
--- /dev/null
+++ b/src/org/apache/http/impl/auth/BasicScheme.java
@@ -0,0 +1,185 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/BasicScheme.java $
+ * $Revision: 658430 $
+ * $Date: 2008-05-20 14:04:27 -0700 (Tue, 20 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.Header;
+import org.apache.http.HttpRequest;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.auth.params.AuthParams;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.EncodingUtils;
+
+/**
+ * <p>
+ * Basic authentication scheme as defined in RFC 2617.
+ * </p>
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author Rodney Waldhoff
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author Ortwin Glueck
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+
+public class BasicScheme extends RFC2617Scheme {
+
+ /** Whether the basic authentication process is complete */
+ private boolean complete;
+
+ /**
+ * Default constructor for the basic authetication scheme.
+ */
+ public BasicScheme() {
+ super();
+ this.complete = false;
+ }
+
+ /**
+ * Returns textual designation of the basic authentication scheme.
+ *
+ * @return <code>basic</code>
+ */
+ public String getSchemeName() {
+ return "basic";
+ }
+
+ /**
+ * Processes the Basic challenge.
+ *
+ * @param header the challenge header
+ *
+ * @throws MalformedChallengeException is thrown if the authentication challenge
+ * is malformed
+ */
+ @Override
+ public void processChallenge(
+ final Header header) throws MalformedChallengeException {
+ super.processChallenge(header);
+ this.complete = true;
+ }
+
+ /**
+ * Tests if the Basic authentication process has been completed.
+ *
+ * @return <tt>true</tt> if Basic authorization has been processed,
+ * <tt>false</tt> otherwise.
+ */
+ public boolean isComplete() {
+ return this.complete;
+ }
+
+ /**
+ * Returns <tt>false</tt>. Basic authentication scheme is request based.
+ *
+ * @return <tt>false</tt>.
+ */
+ public boolean isConnectionBased() {
+ return false;
+ }
+
+ /**
+ * Produces basic authorization header for the given set of {@link Credentials}.
+ *
+ * @param credentials The set of credentials to be used for athentication
+ * @param request The request being authenticated
+ * @throws org.apache.http.auth.InvalidCredentialsException if authentication credentials
+ * are not valid or not applicable for this authentication scheme
+ * @throws AuthenticationException if authorization string cannot
+ * be generated due to an authentication failure
+ *
+ * @return a basic authorization string
+ */
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request) throws AuthenticationException {
+
+ if (credentials == null) {
+ throw new IllegalArgumentException("Credentials may not be null");
+ }
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+
+ String charset = AuthParams.getCredentialCharset(request.getParams());
+ return authenticate(credentials, charset, isProxy());
+ }
+
+ /**
+ * Returns a basic <tt>Authorization</tt> header value for the given
+ * {@link Credentials} and charset.
+ *
+ * @param credentials The credentials to encode.
+ * @param charset The charset to use for encoding the credentials
+ *
+ * @return a basic authorization header
+ */
+ public static Header authenticate(
+ final Credentials credentials,
+ final String charset,
+ boolean proxy) {
+ if (credentials == null) {
+ throw new IllegalArgumentException("Credentials may not be null");
+ }
+ if (charset == null) {
+ throw new IllegalArgumentException("charset may not be null");
+ }
+
+ StringBuilder tmp = new StringBuilder();
+ tmp.append(credentials.getUserPrincipal().getName());
+ tmp.append(":");
+ tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
+
+ byte[] base64password = Base64.encodeBase64(
+ EncodingUtils.getBytes(tmp.toString(), charset));
+
+ CharArrayBuffer buffer = new CharArrayBuffer(32);
+ if (proxy) {
+ buffer.append(AUTH.PROXY_AUTH_RESP);
+ } else {
+ buffer.append(AUTH.WWW_AUTH_RESP);
+ }
+ buffer.append(": Basic ");
+ buffer.append(base64password, 0, base64password.length);
+
+ return new BufferedHeader(buffer);
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/BasicSchemeFactory.java b/src/org/apache/http/impl/auth/BasicSchemeFactory.java
new file mode 100644
index 0000000..c5d28b0
--- /dev/null
+++ b/src/org/apache/http/impl/auth/BasicSchemeFactory.java
@@ -0,0 +1,50 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/BasicSchemeFactory.java $
+ * $Revision: 534839 $
+ * $Date: 2007-05-03 06:03:41 -0700 (Thu, 03 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthSchemeFactory;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class BasicSchemeFactory implements AuthSchemeFactory {
+
+ public AuthScheme newInstance(final HttpParams params) {
+ return new BasicScheme();
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/DigestScheme.java b/src/org/apache/http/impl/auth/DigestScheme.java
new file mode 100644
index 0000000..803807b
--- /dev/null
+++ b/src/org/apache/http/impl/auth/DigestScheme.java
@@ -0,0 +1,484 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/DigestScheme.java $
+ * $Revision: 659595 $
+ * $Date: 2008-05-23 09:47:14 -0700 (Fri, 23 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.apache.http.Header;
+import org.apache.http.HttpRequest;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.auth.params.AuthParams;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.message.BasicHeaderValueFormatter;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.EncodingUtils;
+
+/**
+ * <p>
+ * Digest authentication scheme as defined in RFC 2617.
+ * Both MD5 (default) and MD5-sess are supported.
+ * Currently only qop=auth or no qop is supported. qop=auth-int
+ * is unsupported. If auth and auth-int are provided, auth is
+ * used.
+ * </p>
+ * <p>
+ * Credential charset is configured via the
+ * {@link org.apache.http.auth.params.AuthPNames#CREDENTIAL_CHARSET
+ * credential charset} parameter.
+ * Since the digest username is included as clear text in the generated
+ * Authentication header, the charset of the username must be compatible
+ * with the
+ * {@link org.apache.http.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET
+ * http element charset}.
+ * </p>
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author Rodney Waldhoff
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author Ortwin Glueck
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+
+public class DigestScheme extends RFC2617Scheme {
+
+ /**
+ * Hexa values used when creating 32 character long digest in HTTP DigestScheme
+ * in case of authentication.
+ *
+ * @see #encode(byte[])
+ */
+ private static final char[] HEXADECIMAL = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
+ 'e', 'f'
+ };
+
+ /** Whether the digest authentication process is complete */
+ private boolean complete;
+
+ //TODO: supply a real nonce-count, currently a server will interprete a repeated request as a replay
+ private static final String NC = "00000001"; //nonce-count is always 1
+ private static final int QOP_MISSING = 0;
+ private static final int QOP_AUTH_INT = 1;
+ private static final int QOP_AUTH = 2;
+
+ private int qopVariant = QOP_MISSING;
+ private String cnonce;
+
+ /**
+ * Default constructor for the digest authetication scheme.
+ */
+ public DigestScheme() {
+ super();
+ this.complete = false;
+ }
+
+ /**
+ * Processes the Digest challenge.
+ *
+ * @param header the challenge header
+ *
+ * @throws MalformedChallengeException is thrown if the authentication challenge
+ * is malformed
+ */
+ @Override
+ public void processChallenge(
+ final Header header) throws MalformedChallengeException {
+ super.processChallenge(header);
+
+ if (getParameter("realm") == null) {
+ throw new MalformedChallengeException("missing realm in challange");
+ }
+ if (getParameter("nonce") == null) {
+ throw new MalformedChallengeException("missing nonce in challange");
+ }
+
+ boolean unsupportedQop = false;
+ // qop parsing
+ String qop = getParameter("qop");
+ if (qop != null) {
+ StringTokenizer tok = new StringTokenizer(qop,",");
+ while (tok.hasMoreTokens()) {
+ String variant = tok.nextToken().trim();
+ if (variant.equals("auth")) {
+ qopVariant = QOP_AUTH;
+ break; //that's our favourite, because auth-int is unsupported
+ } else if (variant.equals("auth-int")) {
+ qopVariant = QOP_AUTH_INT;
+ } else {
+ unsupportedQop = true;
+ }
+ }
+ }
+
+ if (unsupportedQop && (qopVariant == QOP_MISSING)) {
+ throw new MalformedChallengeException("None of the qop methods is supported");
+ }
+ // Reset cnonce
+ this.cnonce = null;
+ this.complete = true;
+ }
+
+ /**
+ * Tests if the Digest authentication process has been completed.
+ *
+ * @return <tt>true</tt> if Digest authorization has been processed,
+ * <tt>false</tt> otherwise.
+ */
+ public boolean isComplete() {
+ String s = getParameter("stale");
+ if ("true".equalsIgnoreCase(s)) {
+ return false;
+ } else {
+ return this.complete;
+ }
+ }
+
+ /**
+ * Returns textual designation of the digest authentication scheme.
+ *
+ * @return <code>digest</code>
+ */
+ public String getSchemeName() {
+ return "digest";
+ }
+
+ /**
+ * Returns <tt>false</tt>. Digest authentication scheme is request based.
+ *
+ * @return <tt>false</tt>.
+ */
+ public boolean isConnectionBased() {
+ return false;
+ }
+
+ public void overrideParamter(final String name, final String value) {
+ getParameters().put(name, value);
+ }
+
+ private String getCnonce() {
+ if (this.cnonce == null) {
+ this.cnonce = createCnonce();
+ }
+ return this.cnonce;
+ }
+
+ /**
+ * Produces a digest authorization string for the given set of
+ * {@link Credentials}, method name and URI.
+ *
+ * @param credentials A set of credentials to be used for athentication
+ * @param request The request being authenticated
+ *
+ * @throws org.apache.http.auth.InvalidCredentialsException if authentication credentials
+ * are not valid or not applicable for this authentication scheme
+ * @throws AuthenticationException if authorization string cannot
+ * be generated due to an authentication failure
+ *
+ * @return a digest authorization string
+ */
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request) throws AuthenticationException {
+
+ if (credentials == null) {
+ throw new IllegalArgumentException("Credentials may not be null");
+ }
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+
+ // Add method name and request-URI to the parameter map
+ getParameters().put("methodname", request.getRequestLine().getMethod());
+ getParameters().put("uri", request.getRequestLine().getUri());
+ String charset = getParameter("charset");
+ if (charset == null) {
+ charset = AuthParams.getCredentialCharset(request.getParams());
+ getParameters().put("charset", charset);
+ }
+ String digest = createDigest(credentials);
+ return createDigestHeader(credentials, digest);
+ }
+
+ private static MessageDigest createMessageDigest(
+ final String digAlg) throws UnsupportedDigestAlgorithmException {
+ try {
+ return MessageDigest.getInstance(digAlg);
+ } catch (Exception e) {
+ throw new UnsupportedDigestAlgorithmException(
+ "Unsupported algorithm in HTTP Digest authentication: "
+ + digAlg);
+ }
+ }
+
+ /**
+ * Creates an MD5 response digest.
+ *
+ * @return The created digest as string. This will be the response tag's
+ * value in the Authentication HTTP header.
+ * @throws AuthenticationException when MD5 is an unsupported algorithm
+ */
+ private String createDigest(final Credentials credentials) throws AuthenticationException {
+ // Collecting required tokens
+ String uri = getParameter("uri");
+ String realm = getParameter("realm");
+ String nonce = getParameter("nonce");
+ String method = getParameter("methodname");
+ String algorithm = getParameter("algorithm");
+ if (uri == null) {
+ throw new IllegalStateException("URI may not be null");
+ }
+ if (realm == null) {
+ throw new IllegalStateException("Realm may not be null");
+ }
+ if (nonce == null) {
+ throw new IllegalStateException("Nonce may not be null");
+ }
+ // If an algorithm is not specified, default to MD5.
+ if (algorithm == null) {
+ algorithm = "MD5";
+ }
+ // If an charset is not specified, default to ISO-8859-1.
+ String charset = getParameter("charset");
+ if (charset == null) {
+ charset = "ISO-8859-1";
+ }
+
+ if (qopVariant == QOP_AUTH_INT) {
+ throw new AuthenticationException(
+ "Unsupported qop in HTTP Digest authentication");
+ }
+
+ MessageDigest md5Helper = createMessageDigest("MD5");
+
+ String uname = credentials.getUserPrincipal().getName();
+ String pwd = credentials.getPassword();
+
+ // 3.2.2.2: Calculating digest
+ StringBuilder tmp = new StringBuilder(uname.length() + realm.length() + pwd.length() + 2);
+ tmp.append(uname);
+ tmp.append(':');
+ tmp.append(realm);
+ tmp.append(':');
+ tmp.append(pwd);
+ // unq(username-value) ":" unq(realm-value) ":" passwd
+ String a1 = tmp.toString();
+
+ //a1 is suitable for MD5 algorithm
+ if(algorithm.equals("MD5-sess")) {
+ // H( unq(username-value) ":" unq(realm-value) ":" passwd )
+ // ":" unq(nonce-value)
+ // ":" unq(cnonce-value)
+
+ String cnonce = getCnonce();
+
+ String tmp2=encode(md5Helper.digest(EncodingUtils.getBytes(a1, charset)));
+ StringBuilder tmp3 = new StringBuilder(tmp2.length() + nonce.length() + cnonce.length() + 2);
+ tmp3.append(tmp2);
+ tmp3.append(':');
+ tmp3.append(nonce);
+ tmp3.append(':');
+ tmp3.append(cnonce);
+ a1 = tmp3.toString();
+ } else if (!algorithm.equals("MD5")) {
+ throw new AuthenticationException("Unhandled algorithm " + algorithm + " requested");
+ }
+ String md5a1 = encode(md5Helper.digest(EncodingUtils.getBytes(a1, charset)));
+
+ String a2 = null;
+ if (qopVariant == QOP_AUTH_INT) {
+ // Unhandled qop auth-int
+ //we do not have access to the entity-body or its hash
+ //TODO: add Method ":" digest-uri-value ":" H(entity-body)
+ } else {
+ a2 = method + ':' + uri;
+ }
+ String md5a2 = encode(md5Helper.digest(EncodingUtils.getAsciiBytes(a2)));
+
+ // 3.2.2.1
+ String serverDigestValue;
+ if (qopVariant == QOP_MISSING) {
+ StringBuilder tmp2 = new StringBuilder(md5a1.length() + nonce.length() + md5a2.length());
+ tmp2.append(md5a1);
+ tmp2.append(':');
+ tmp2.append(nonce);
+ tmp2.append(':');
+ tmp2.append(md5a2);
+ serverDigestValue = tmp2.toString();
+ } else {
+ String qopOption = getQopVariantString();
+ String cnonce = getCnonce();
+
+ StringBuilder tmp2 = new StringBuilder(md5a1.length() + nonce.length()
+ + NC.length() + cnonce.length() + qopOption.length() + md5a2.length() + 5);
+ tmp2.append(md5a1);
+ tmp2.append(':');
+ tmp2.append(nonce);
+ tmp2.append(':');
+ tmp2.append(NC);
+ tmp2.append(':');
+ tmp2.append(cnonce);
+ tmp2.append(':');
+ tmp2.append(qopOption);
+ tmp2.append(':');
+ tmp2.append(md5a2);
+ serverDigestValue = tmp2.toString();
+ }
+
+ String serverDigest =
+ encode(md5Helper.digest(EncodingUtils.getAsciiBytes(serverDigestValue)));
+
+ return serverDigest;
+ }
+
+ /**
+ * Creates digest-response header as defined in RFC2617.
+ *
+ * @param credentials User credentials
+ * @param digest The response tag's value as String.
+ *
+ * @return The digest-response as String.
+ */
+ private Header createDigestHeader(
+ final Credentials credentials,
+ final String digest) throws AuthenticationException {
+
+ CharArrayBuffer buffer = new CharArrayBuffer(128);
+ if (isProxy()) {
+ buffer.append(AUTH.PROXY_AUTH_RESP);
+ } else {
+ buffer.append(AUTH.WWW_AUTH_RESP);
+ }
+ buffer.append(": Digest ");
+
+ String uri = getParameter("uri");
+ String realm = getParameter("realm");
+ String nonce = getParameter("nonce");
+ String opaque = getParameter("opaque");
+ String response = digest;
+ String algorithm = getParameter("algorithm");
+
+ String uname = credentials.getUserPrincipal().getName();
+
+ List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(20);
+ params.add(new BasicNameValuePair("username", uname));
+ params.add(new BasicNameValuePair("realm", realm));
+ params.add(new BasicNameValuePair("nonce", nonce));
+ params.add(new BasicNameValuePair("uri", uri));
+ params.add(new BasicNameValuePair("response", response));
+
+ if (qopVariant != QOP_MISSING) {
+ params.add(new BasicNameValuePair("qop", getQopVariantString()));
+ params.add(new BasicNameValuePair("nc", NC));
+ params.add(new BasicNameValuePair("cnonce", getCnonce()));
+ }
+ if (algorithm != null) {
+ params.add(new BasicNameValuePair("algorithm", algorithm));
+ }
+ if (opaque != null) {
+ params.add(new BasicNameValuePair("opaque", opaque));
+ }
+
+ for (int i = 0; i < params.size(); i++) {
+ BasicNameValuePair param = params.get(i);
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ boolean noQuotes = "nc".equals(param.getName()) ||
+ "qop".equals(param.getName());
+ BasicHeaderValueFormatter.DEFAULT
+ .formatNameValuePair(buffer, param, !noQuotes);
+ }
+ return new BufferedHeader(buffer);
+ }
+
+ private String getQopVariantString() {
+ String qopOption;
+ if (qopVariant == QOP_AUTH_INT) {
+ qopOption = "auth-int";
+ } else {
+ qopOption = "auth";
+ }
+ return qopOption;
+ }
+
+ /**
+ * Encodes the 128 bit (16 bytes) MD5 digest into a 32 characters long
+ * <CODE>String</CODE> according to RFC 2617.
+ *
+ * @param binaryData array containing the digest
+ * @return encoded MD5, or <CODE>null</CODE> if encoding failed
+ */
+ private static String encode(byte[] binaryData) {
+ if (binaryData.length != 16) {
+ return null;
+ }
+
+ char[] buffer = new char[32];
+ for (int i = 0; i < 16; i++) {
+ int low = (binaryData[i] & 0x0f);
+ int high = ((binaryData[i] & 0xf0) >> 4);
+ buffer[i * 2] = HEXADECIMAL[high];
+ buffer[(i * 2) + 1] = HEXADECIMAL[low];
+ }
+
+ return new String(buffer);
+ }
+
+
+ /**
+ * Creates a random cnonce value based on the current time.
+ *
+ * @return The cnonce value as String.
+ * @throws UnsupportedDigestAlgorithmException if MD5 algorithm is not supported.
+ */
+ public static String createCnonce() {
+ String cnonce;
+
+ MessageDigest md5Helper = createMessageDigest("MD5");
+
+ cnonce = Long.toString(System.currentTimeMillis());
+ cnonce = encode(md5Helper.digest(EncodingUtils.getAsciiBytes(cnonce)));
+
+ return cnonce;
+ }
+}
diff --git a/src/org/apache/http/impl/auth/DigestSchemeFactory.java b/src/org/apache/http/impl/auth/DigestSchemeFactory.java
new file mode 100644
index 0000000..38f2e12
--- /dev/null
+++ b/src/org/apache/http/impl/auth/DigestSchemeFactory.java
@@ -0,0 +1,50 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/DigestSchemeFactory.java $
+ * $Revision: 534839 $
+ * $Date: 2007-05-03 06:03:41 -0700 (Thu, 03 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthSchemeFactory;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class DigestSchemeFactory implements AuthSchemeFactory {
+
+ public AuthScheme newInstance(final HttpParams params) {
+ return new DigestScheme();
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/NTLMEngine.java b/src/org/apache/http/impl/auth/NTLMEngine.java
new file mode 100644
index 0000000..7b6bf42
--- /dev/null
+++ b/src/org/apache/http/impl/auth/NTLMEngine.java
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/NTLMEngine.java $
+ * $Revision: 659788 $
+ * $Date: 2008-05-24 03:42:23 -0700 (Sat, 24 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+/**
+ * Abstract NTLM authentication engine. The engine can be used to
+ * generate Type1 messages and Type3 messages in response to a
+ * Type2 challenge.
+ * <p/>
+ * For details see <a href="http://davenport.sourceforge.net/ntlm.html">this resource</a>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+*/
+public interface NTLMEngine {
+
+ /**
+ * Generates a Type1 message given the domain and workstation.
+ *
+ * @param domain Optional Windows domain name. Can be <code>null</code>.
+ * @param workstation Optional Windows workstation name. Can be
+ * <code>null</code>.
+ * @return Type1 message
+ * @throws NTLMEngineException
+ */
+ String generateType1Msg(
+ String domain,
+ String workstation) throws NTLMEngineException;
+
+ /**
+ * Generates a Type3 message given the user credentials and the
+ * authentication challenge.
+ *
+ * @param username Windows user name
+ * @param password Password
+ * @param domain Windows domain name
+ * @param workstation Windows workstation name
+ * @param challenge Type2 challenge.
+ * @return Type3 response.
+ * @throws NTLMEngineException
+ */
+ String generateType3Msg(
+ String username,
+ String password,
+ String domain,
+ String workstation,
+ String challenge) throws NTLMEngineException;
+
+}
diff --git a/src/org/apache/http/impl/auth/NTLMEngineException.java b/src/org/apache/http/impl/auth/NTLMEngineException.java
new file mode 100644
index 0000000..73baabc
--- /dev/null
+++ b/src/org/apache/http/impl/auth/NTLMEngineException.java
@@ -0,0 +1,70 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/NTLMEngineException.java $
+ * $Revision: 655048 $
+ * $Date: 2008-05-10 04:22:12 -0700 (Sat, 10 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.auth.AuthenticationException;
+
+/**
+ * Signals NTLM protocol failure.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class NTLMEngineException extends AuthenticationException {
+
+ private static final long serialVersionUID = 6027981323731768824L;
+
+ public NTLMEngineException() {
+ super();
+ }
+
+ /**
+ * Creates a new NTLMEngineException with the specified message.
+ *
+ * @param message the exception detail message
+ */
+ public NTLMEngineException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new NTLMEngineException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public NTLMEngineException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/NTLMScheme.java b/src/org/apache/http/impl/auth/NTLMScheme.java
new file mode 100644
index 0000000..8dfdbba
--- /dev/null
+++ b/src/org/apache/http/impl/auth/NTLMScheme.java
@@ -0,0 +1,149 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/NTLMScheme.java $
+ * $Revision: 655048 $
+ * $Date: 2008-05-10 04:22:12 -0700 (Sat, 10 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.Header;
+import org.apache.http.HttpRequest;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.InvalidCredentialsException;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.auth.NTCredentials;
+import org.apache.http.impl.auth.AuthSchemeBase;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.util.CharArrayBuffer;
+
+public class NTLMScheme extends AuthSchemeBase {
+
+ enum State {
+ UNINITIATED,
+ CHALLENGE_RECEIVED,
+ MSG_TYPE1_GENERATED,
+ MSG_TYPE2_RECEVIED,
+ MSG_TYPE3_GENERATED,
+ FAILED,
+ }
+
+ private final NTLMEngine engine;
+
+ private State state;
+ private String challenge;
+
+ public NTLMScheme(final NTLMEngine engine) {
+ super();
+ if (engine == null) {
+ throw new IllegalArgumentException("NTLM engine may not be null");
+ }
+ this.engine = engine;
+ this.state = State.UNINITIATED;
+ this.challenge = null;
+ }
+
+ public String getSchemeName() {
+ return "ntlm";
+ }
+
+ public String getParameter(String name) {
+ // String parameters not supported
+ return null;
+ }
+
+ public String getRealm() {
+ // NTLM does not support the concept of an authentication realm
+ return null;
+ }
+
+ public boolean isConnectionBased() {
+ return true;
+ }
+
+ @Override
+ protected void parseChallenge(
+ final CharArrayBuffer buffer, int pos, int len) throws MalformedChallengeException {
+ String challenge = buffer.substringTrimmed(pos, len);
+ if (challenge.length() == 0) {
+ if (this.state == State.UNINITIATED) {
+ this.state = State.CHALLENGE_RECEIVED;
+ } else {
+ this.state = State.FAILED;
+ }
+ this.challenge = null;
+ } else {
+ this.state = State.MSG_TYPE2_RECEVIED;
+ this.challenge = challenge;
+ }
+ }
+
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request) throws AuthenticationException {
+ NTCredentials ntcredentials = null;
+ try {
+ ntcredentials = (NTCredentials) credentials;
+ } catch (ClassCastException e) {
+ throw new InvalidCredentialsException(
+ "Credentials cannot be used for NTLM authentication: "
+ + credentials.getClass().getName());
+ }
+ String response = null;
+ if (this.state == State.CHALLENGE_RECEIVED || this.state == State.FAILED) {
+ response = this.engine.generateType1Msg(
+ ntcredentials.getDomain(),
+ ntcredentials.getWorkstation());
+ this.state = State.MSG_TYPE1_GENERATED;
+ } else if (this.state == State.MSG_TYPE2_RECEVIED) {
+ response = this.engine.generateType3Msg(
+ ntcredentials.getUserName(),
+ ntcredentials.getPassword(),
+ ntcredentials.getDomain(),
+ ntcredentials.getWorkstation(),
+ this.challenge);
+ this.state = State.MSG_TYPE3_GENERATED;
+ } else {
+ throw new AuthenticationException("Unexpected state: " + this.state);
+ }
+ CharArrayBuffer buffer = new CharArrayBuffer(32);
+ if (isProxy()) {
+ buffer.append(AUTH.PROXY_AUTH_RESP);
+ } else {
+ buffer.append(AUTH.WWW_AUTH_RESP);
+ }
+ buffer.append(": NTLM ");
+ buffer.append(response);
+ return new BufferedHeader(buffer);
+ }
+
+ public boolean isComplete() {
+ return this.state == State.MSG_TYPE3_GENERATED || this.state == State.FAILED;
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/RFC2617Scheme.java b/src/org/apache/http/impl/auth/RFC2617Scheme.java
new file mode 100644
index 0000000..0ed0a28
--- /dev/null
+++ b/src/org/apache/http/impl/auth/RFC2617Scheme.java
@@ -0,0 +1,119 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java $
+ * $Revision: 659595 $
+ * $Date: 2008-05-23 09:47:14 -0700 (Fri, 23 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.message.BasicHeaderValueParser;
+import org.apache.http.message.HeaderValueParser;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Abstract authentication scheme class that lays foundation for all
+ * RFC 2617 compliant authetication schemes and provides capabilities common
+ * to all authentication schemes defined in RFC 2617.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+*/
+public abstract class RFC2617Scheme extends AuthSchemeBase {
+
+ /**
+ * Authentication parameter map.
+ */
+ private Map<String, String> params;
+
+ /**
+ * Default constructor for RFC2617 compliant authetication schemes.
+ */
+ public RFC2617Scheme() {
+ super();
+ }
+
+ @Override
+ protected void parseChallenge(
+ final CharArrayBuffer buffer, int pos, int len) throws MalformedChallengeException {
+ HeaderValueParser parser = BasicHeaderValueParser.DEFAULT;
+ ParserCursor cursor = new ParserCursor(pos, buffer.length());
+ HeaderElement[] elements = parser.parseElements(buffer, cursor);
+ if (elements.length == 0) {
+ throw new MalformedChallengeException("Authentication challenge is empty");
+ }
+
+ this.params = new HashMap<String, String>(elements.length);
+ for (HeaderElement element : elements) {
+ this.params.put(element.getName(), element.getValue());
+ }
+ }
+
+ /**
+ * Returns authentication parameters map. Keys in the map are lower-cased.
+ *
+ * @return the map of authentication parameters
+ */
+ protected Map<String, String> getParameters() {
+ if (this.params == null) {
+ this.params = new HashMap<String, String>();
+ }
+ return this.params;
+ }
+
+ /**
+ * Returns authentication parameter with the given name, if available.
+ *
+ * @param name The name of the parameter to be returned
+ *
+ * @return the parameter with the given name
+ */
+ public String getParameter(final String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Parameter name may not be null");
+ }
+ if (this.params == null) {
+ return null;
+ }
+ return this.params.get(name.toLowerCase(Locale.ENGLISH));
+ }
+
+ /**
+ * Returns authentication realm. The realm may not be null.
+ *
+ * @return the authentication realm
+ */
+ public String getRealm() {
+ return getParameter("realm");
+ }
+
+}
diff --git a/src/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java b/src/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java
new file mode 100644
index 0000000..abd0a66
--- /dev/null
+++ b/src/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java
@@ -0,0 +1,71 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java $
+ * $Revision: 527479 $
+ * $Date: 2007-04-11 05:55:12 -0700 (Wed, 11 Apr 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+/**
+ * Authentication credentials required to respond to a authentication
+ * challenge are invalid
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class UnsupportedDigestAlgorithmException extends RuntimeException {
+
+ private static final long serialVersionUID = 319558534317118022L;
+
+ /**
+ * Creates a new UnsupportedAuthAlgoritmException with a <tt>null</tt> detail message.
+ */
+ public UnsupportedDigestAlgorithmException() {
+ super();
+ }
+
+ /**
+ * Creates a new UnsupportedAuthAlgoritmException with the specified message.
+ *
+ * @param message the exception detail message
+ */
+ public UnsupportedDigestAlgorithmException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new UnsupportedAuthAlgoritmException with the specified detail message and cause.
+ *
+ * @param message the exception detail message
+ * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
+ * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+ */
+ public UnsupportedDigestAlgorithmException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/org/apache/http/impl/auth/package.html b/src/org/apache/http/impl/auth/package.html
new file mode 100644
index 0000000..e301283
--- /dev/null
+++ b/src/org/apache/http/impl/auth/package.html
@@ -0,0 +1,4 @@
+<body>
+
+</body>
+
diff --git a/src/org/apache/http/impl/client/AbstractAuthenticationHandler.java b/src/org/apache/http/impl/client/AbstractAuthenticationHandler.java
new file mode 100644
index 0000000..57699d5
--- /dev/null
+++ b/src/org/apache/http/impl/client/AbstractAuthenticationHandler.java
@@ -0,0 +1,165 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractAuthenticationHandler.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthSchemeRegistry;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.client.AuthenticationHandler;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public abstract class AbstractAuthenticationHandler implements AuthenticationHandler {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ private static final List<String> DEFAULT_SCHEME_PRIORITY = Arrays.asList(new String[] {
+ "ntlm",
+ "digest",
+ "basic"
+ });
+
+ public AbstractAuthenticationHandler() {
+ super();
+ }
+
+ protected Map<String, Header> parseChallenges(
+ final Header[] headers) throws MalformedChallengeException {
+
+ Map<String, Header> map = new HashMap<String, Header>(headers.length);
+ for (Header header : headers) {
+ CharArrayBuffer buffer;
+ int pos;
+ if (header instanceof FormattedHeader) {
+ buffer = ((FormattedHeader) header).getBuffer();
+ pos = ((FormattedHeader) header).getValuePos();
+ } else {
+ String s = header.getValue();
+ if (s == null) {
+ throw new MalformedChallengeException("Header value is null");
+ }
+ buffer = new CharArrayBuffer(s.length());
+ buffer.append(s);
+ pos = 0;
+ }
+ while (pos < buffer.length() && HTTP.isWhitespace(buffer.charAt(pos))) {
+ pos++;
+ }
+ int beginIndex = pos;
+ while (pos < buffer.length() && !HTTP.isWhitespace(buffer.charAt(pos))) {
+ pos++;
+ }
+ int endIndex = pos;
+ String s = buffer.substring(beginIndex, endIndex);
+ map.put(s.toLowerCase(Locale.ENGLISH), header);
+ }
+ return map;
+ }
+
+ protected List<String> getAuthPreferences() {
+ return DEFAULT_SCHEME_PRIORITY;
+ }
+
+ public AuthScheme selectScheme(
+ final Map<String, Header> challenges,
+ final HttpResponse response,
+ final HttpContext context) throws AuthenticationException {
+
+ AuthSchemeRegistry registry = (AuthSchemeRegistry) context.getAttribute(
+ ClientContext.AUTHSCHEME_REGISTRY);
+ if (registry == null) {
+ throw new IllegalStateException("AuthScheme registry not set in HTTP context");
+ }
+
+ List<?> authPrefs = (List<?>) context.getAttribute(
+ ClientContext.AUTH_SCHEME_PREF);
+ if (authPrefs == null) {
+ authPrefs = getAuthPreferences();
+ }
+
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Authentication schemes in the order of preference: "
+ + authPrefs);
+ }
+
+ AuthScheme authScheme = null;
+ for (int i = 0; i < authPrefs.size(); i++) {
+ String id = (String) authPrefs.get(i);
+ Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
+
+ if (challenge != null) {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug(id + " authentication scheme selected");
+ }
+ try {
+ authScheme = registry.getAuthScheme(id, response.getParams());
+ break;
+ } catch (IllegalStateException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("Authentication scheme " + id + " not supported");
+ // Try again
+ }
+ }
+ } else {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Challenge for " + id + " authentication scheme not available");
+ // Try again
+ }
+ }
+ }
+ if (authScheme == null) {
+ // If none selected, something is wrong
+ throw new AuthenticationException(
+ "Unable to respond to any of these challenges: "
+ + challenges);
+ }
+ return authScheme;
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/AbstractHttpClient.java b/src/org/apache/http/impl/client/AbstractHttpClient.java
new file mode 100644
index 0000000..3a1b838
--- /dev/null
+++ b/src/org/apache/http/impl/client/AbstractHttpClient.java
@@ -0,0 +1,697 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java $
+ * $Revision: 677250 $
+ * $Date: 2008-07-16 04:45:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.io.IOException;
+import java.net.URI;
+import java.lang.reflect.UndeclaredThrowableException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpEntity;
+import org.apache.http.auth.AuthSchemeRegistry;
+import org.apache.http.client.AuthenticationHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.RequestDirector;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.cookie.CookieSpecRegistry;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.DefaultedHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestExecutor;
+
+/**
+ * Convenience base class for HTTP client implementations.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 677250 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractHttpClient implements HttpClient {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The parameters. */
+ private HttpParams defaultParams;
+
+ /** The request executor. */
+ private HttpRequestExecutor requestExec;
+
+ /** The connection manager. */
+ private ClientConnectionManager connManager;
+
+ /** The connection re-use strategy. */
+ private ConnectionReuseStrategy reuseStrategy;
+
+ /** The connection keep-alive strategy. */
+ private ConnectionKeepAliveStrategy keepAliveStrategy;
+
+ /** The cookie spec registry. */
+ private CookieSpecRegistry supportedCookieSpecs;
+
+ /** The authentication scheme registry. */
+ private AuthSchemeRegistry supportedAuthSchemes;
+
+ /** The HTTP processor. */
+ private BasicHttpProcessor httpProcessor;
+
+ /** The request retry handler. */
+ private HttpRequestRetryHandler retryHandler;
+
+ /** The redirect handler. */
+ private RedirectHandler redirectHandler;
+
+ /** The target authentication handler. */
+ private AuthenticationHandler targetAuthHandler;
+
+ /** The proxy authentication handler. */
+ private AuthenticationHandler proxyAuthHandler;
+
+ /** The cookie store. */
+ private CookieStore cookieStore;
+
+ /** The credentials provider. */
+ private CredentialsProvider credsProvider;
+
+ /** The route planner. */
+ private HttpRoutePlanner routePlanner;
+
+ /** The user token handler. */
+ private UserTokenHandler userTokenHandler;
+
+
+ /**
+ * Creates a new HTTP client.
+ *
+ * @param conman the connection manager
+ * @param params the parameters
+ */
+ protected AbstractHttpClient(
+ final ClientConnectionManager conman,
+ final HttpParams params) {
+ defaultParams = params;
+ connManager = conman;
+ } // constructor
+
+ protected abstract HttpParams createHttpParams();
+
+
+ protected abstract HttpContext createHttpContext();
+
+
+ protected abstract HttpRequestExecutor createRequestExecutor();
+
+
+ protected abstract ClientConnectionManager createClientConnectionManager();
+
+
+ protected abstract AuthSchemeRegistry createAuthSchemeRegistry();
+
+
+ protected abstract CookieSpecRegistry createCookieSpecRegistry();
+
+
+ protected abstract ConnectionReuseStrategy createConnectionReuseStrategy();
+
+
+ protected abstract ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy();
+
+
+ protected abstract BasicHttpProcessor createHttpProcessor();
+
+
+ protected abstract HttpRequestRetryHandler createHttpRequestRetryHandler();
+
+
+ protected abstract RedirectHandler createRedirectHandler();
+
+
+ protected abstract AuthenticationHandler createTargetAuthenticationHandler();
+
+
+ protected abstract AuthenticationHandler createProxyAuthenticationHandler();
+
+
+ protected abstract CookieStore createCookieStore();
+
+
+ protected abstract CredentialsProvider createCredentialsProvider();
+
+
+ protected abstract HttpRoutePlanner createHttpRoutePlanner();
+
+
+ protected abstract UserTokenHandler createUserTokenHandler();
+
+
+ // non-javadoc, see interface HttpClient
+ public synchronized final HttpParams getParams() {
+ if (defaultParams == null) {
+ defaultParams = createHttpParams();
+ }
+ return defaultParams;
+ }
+
+
+ /**
+ * Replaces the parameters.
+ * The implementation here does not update parameters of dependent objects.
+ *
+ * @param params the new default parameters
+ */
+ public synchronized void setParams(HttpParams params) {
+ defaultParams = params;
+ }
+
+
+ public synchronized final ClientConnectionManager getConnectionManager() {
+ if (connManager == null) {
+ connManager = createClientConnectionManager();
+ }
+ return connManager;
+ }
+
+
+ public synchronized final HttpRequestExecutor getRequestExecutor() {
+ if (requestExec == null) {
+ requestExec = createRequestExecutor();
+ }
+ return requestExec;
+ }
+
+
+ public synchronized final AuthSchemeRegistry getAuthSchemes() {
+ if (supportedAuthSchemes == null) {
+ supportedAuthSchemes = createAuthSchemeRegistry();
+ }
+ return supportedAuthSchemes;
+ }
+
+
+ public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
+ supportedAuthSchemes = authSchemeRegistry;
+ }
+
+
+ public synchronized final CookieSpecRegistry getCookieSpecs() {
+ if (supportedCookieSpecs == null) {
+ supportedCookieSpecs = createCookieSpecRegistry();
+ }
+ return supportedCookieSpecs;
+ }
+
+
+ public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
+ supportedCookieSpecs = cookieSpecRegistry;
+ }
+
+
+ public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
+ if (reuseStrategy == null) {
+ reuseStrategy = createConnectionReuseStrategy();
+ }
+ return reuseStrategy;
+ }
+
+
+ public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
+ this.reuseStrategy = reuseStrategy;
+ }
+
+
+ public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
+ if (keepAliveStrategy == null) {
+ keepAliveStrategy = createConnectionKeepAliveStrategy();
+ }
+ return keepAliveStrategy;
+ }
+
+
+ public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
+ this.keepAliveStrategy = keepAliveStrategy;
+ }
+
+
+ public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
+ if (retryHandler == null) {
+ retryHandler = createHttpRequestRetryHandler();
+ }
+ return retryHandler;
+ }
+
+
+ public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler retryHandler) {
+ this.retryHandler = retryHandler;
+ }
+
+
+ public synchronized final RedirectHandler getRedirectHandler() {
+ if (redirectHandler == null) {
+ redirectHandler = createRedirectHandler();
+ }
+ return redirectHandler;
+ }
+
+
+ public synchronized void setRedirectHandler(final RedirectHandler redirectHandler) {
+ this.redirectHandler = redirectHandler;
+ }
+
+
+ public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
+ if (targetAuthHandler == null) {
+ targetAuthHandler = createTargetAuthenticationHandler();
+ }
+ return targetAuthHandler;
+ }
+
+
+ public synchronized void setTargetAuthenticationHandler(
+ final AuthenticationHandler targetAuthHandler) {
+ this.targetAuthHandler = targetAuthHandler;
+ }
+
+
+ public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
+ if (proxyAuthHandler == null) {
+ proxyAuthHandler = createProxyAuthenticationHandler();
+ }
+ return proxyAuthHandler;
+ }
+
+
+ public synchronized void setProxyAuthenticationHandler(
+ final AuthenticationHandler proxyAuthHandler) {
+ this.proxyAuthHandler = proxyAuthHandler;
+ }
+
+
+ public synchronized final CookieStore getCookieStore() {
+ if (cookieStore == null) {
+ cookieStore = createCookieStore();
+ }
+ return cookieStore;
+ }
+
+
+ public synchronized void setCookieStore(final CookieStore cookieStore) {
+ this.cookieStore = cookieStore;
+ }
+
+
+ public synchronized final CredentialsProvider getCredentialsProvider() {
+ if (credsProvider == null) {
+ credsProvider = createCredentialsProvider();
+ }
+ return credsProvider;
+ }
+
+
+ public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
+ this.credsProvider = credsProvider;
+ }
+
+
+ public synchronized final HttpRoutePlanner getRoutePlanner() {
+ if (this.routePlanner == null) {
+ this.routePlanner = createHttpRoutePlanner();
+ }
+ return this.routePlanner;
+ }
+
+
+ public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
+ this.routePlanner = routePlanner;
+ }
+
+
+ public synchronized final UserTokenHandler getUserTokenHandler() {
+ if (this.userTokenHandler == null) {
+ this.userTokenHandler = createUserTokenHandler();
+ }
+ return this.userTokenHandler;
+ }
+
+
+ public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
+ this.userTokenHandler = userTokenHandler;
+ }
+
+
+ protected synchronized final BasicHttpProcessor getHttpProcessor() {
+ if (httpProcessor == null) {
+ httpProcessor = createHttpProcessor();
+ }
+ return httpProcessor;
+ }
+
+
+ public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
+ getHttpProcessor().addInterceptor(itcp);
+ }
+
+
+ public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, int index) {
+ getHttpProcessor().addInterceptor(itcp, index);
+ }
+
+
+ public synchronized HttpResponseInterceptor getResponseInterceptor(int index) {
+ return getHttpProcessor().getResponseInterceptor(index);
+ }
+
+
+ public synchronized int getResponseInterceptorCount() {
+ return getHttpProcessor().getResponseInterceptorCount();
+ }
+
+
+ public synchronized void clearResponseInterceptors() {
+ getHttpProcessor().clearResponseInterceptors();
+ }
+
+
+ public void removeResponseInterceptorByClass(Class<? extends HttpResponseInterceptor> clazz) {
+ getHttpProcessor().removeResponseInterceptorByClass(clazz);
+ }
+
+
+ public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
+ getHttpProcessor().addInterceptor(itcp);
+ }
+
+
+ public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, int index) {
+ getHttpProcessor().addInterceptor(itcp, index);
+ }
+
+
+ public synchronized HttpRequestInterceptor getRequestInterceptor(int index) {
+ return getHttpProcessor().getRequestInterceptor(index);
+ }
+
+
+ public synchronized int getRequestInterceptorCount() {
+ return getHttpProcessor().getRequestInterceptorCount();
+ }
+
+
+ public synchronized void clearRequestInterceptors() {
+ getHttpProcessor().clearRequestInterceptors();
+ }
+
+
+ public void removeRequestInterceptorByClass(Class<? extends HttpRequestInterceptor> clazz) {
+ getHttpProcessor().removeRequestInterceptorByClass(clazz);
+ }
+
+
+ // non-javadoc, see interface HttpClient
+ public final HttpResponse execute(HttpUriRequest request)
+ throws IOException, ClientProtocolException {
+
+ return execute(request, (HttpContext) null);
+ }
+
+
+ /**
+ * Maps to {@link HttpClient#execute(HttpHost,HttpRequest,HttpContext)
+ * execute(target, request, context)}.
+ * The target is determined from the URI of the request.
+ *
+ * @param request the request to execute
+ * @param context the request-specific execution context,
+ * or <code>null</code> to use a default context
+ */
+ public final HttpResponse execute(HttpUriRequest request,
+ HttpContext context)
+ throws IOException, ClientProtocolException {
+
+ if (request == null) {
+ throw new IllegalArgumentException
+ ("Request must not be null.");
+ }
+
+ return execute(determineTarget(request), request, context);
+ }
+
+ private HttpHost determineTarget(HttpUriRequest request) {
+ // A null target may be acceptable if there is a default target.
+ // Otherwise, the null target is detected in the director.
+ HttpHost target = null;
+
+ URI requestURI = request.getURI();
+ if (requestURI.isAbsolute()) {
+ target = new HttpHost(
+ requestURI.getHost(),
+ requestURI.getPort(),
+ requestURI.getScheme());
+ }
+ return target;
+ }
+
+ // non-javadoc, see interface HttpClient
+ public final HttpResponse execute(HttpHost target, HttpRequest request)
+ throws IOException, ClientProtocolException {
+
+ return execute(target, request, (HttpContext) null);
+ }
+
+
+ // non-javadoc, see interface HttpClient
+ public final HttpResponse execute(HttpHost target, HttpRequest request,
+ HttpContext context)
+ throws IOException, ClientProtocolException {
+
+ if (request == null) {
+ throw new IllegalArgumentException
+ ("Request must not be null.");
+ }
+ // a null target may be acceptable, this depends on the route planner
+ // a null context is acceptable, default context created below
+
+ HttpContext execContext = null;
+ RequestDirector director = null;
+
+ // Initialize the request execution context making copies of
+ // all shared objects that are potentially threading unsafe.
+ synchronized (this) {
+
+ HttpContext defaultContext = createHttpContext();
+ if (context == null) {
+ execContext = defaultContext;
+ } else {
+ execContext = new DefaultedHttpContext(context, defaultContext);
+ }
+ // Create a director for this request
+ director = createClientRequestDirector(
+ getRequestExecutor(),
+ getConnectionManager(),
+ getConnectionReuseStrategy(),
+ getConnectionKeepAliveStrategy(),
+ getRoutePlanner(),
+ getHttpProcessor().copy(),
+ getHttpRequestRetryHandler(),
+ getRedirectHandler(),
+ getTargetAuthenticationHandler(),
+ getProxyAuthenticationHandler(),
+ getUserTokenHandler(),
+ determineParams(request));
+ }
+
+ try {
+ return director.execute(target, request, execContext);
+ } catch(HttpException httpException) {
+ throw new ClientProtocolException(httpException);
+ }
+ } // execute
+
+
+ protected RequestDirector createClientRequestDirector(
+ final HttpRequestExecutor requestExec,
+ final ClientConnectionManager conman,
+ final ConnectionReuseStrategy reustrat,
+ final ConnectionKeepAliveStrategy kastrat,
+ final HttpRoutePlanner rouplan,
+ final HttpProcessor httpProcessor,
+ final HttpRequestRetryHandler retryHandler,
+ final RedirectHandler redirectHandler,
+ final AuthenticationHandler targetAuthHandler,
+ final AuthenticationHandler proxyAuthHandler,
+ final UserTokenHandler stateHandler,
+ final HttpParams params) {
+ return new DefaultRequestDirector(
+ requestExec,
+ conman,
+ reustrat,
+ kastrat,
+ rouplan,
+ httpProcessor,
+ retryHandler,
+ redirectHandler,
+ targetAuthHandler,
+ proxyAuthHandler,
+ stateHandler,
+ params);
+ }
+
+ /**
+ * Obtains parameters for executing a request.
+ * The default implementation in this class creates a new
+ * {@link ClientParamsStack} from the request parameters
+ * and the client parameters.
+ * <br/>
+ * This method is called by the default implementation of
+ * {@link #execute(HttpHost,HttpRequest,HttpContext)}
+ * to obtain the parameters for the
+ * {@link DefaultRequestDirector}.
+ *
+ * @param req the request that will be executed
+ *
+ * @return the parameters to use
+ */
+ protected HttpParams determineParams(HttpRequest req) {
+ return new ClientParamsStack
+ (null, getParams(), req.getParams(), null);
+ }
+
+
+ // non-javadoc, see interface HttpClient
+ public <T> T execute(
+ final HttpUriRequest request,
+ final ResponseHandler<? extends T> responseHandler)
+ throws IOException, ClientProtocolException {
+ return execute(request, responseHandler, null);
+ }
+
+
+ // non-javadoc, see interface HttpClient
+ public <T> T execute(
+ final HttpUriRequest request,
+ final ResponseHandler<? extends T> responseHandler,
+ final HttpContext context)
+ throws IOException, ClientProtocolException {
+ HttpHost target = determineTarget(request);
+ return execute(target, request, responseHandler, context);
+ }
+
+
+ // non-javadoc, see interface HttpClient
+ public <T> T execute(
+ final HttpHost target,
+ final HttpRequest request,
+ final ResponseHandler<? extends T> responseHandler)
+ throws IOException, ClientProtocolException {
+ return execute(target, request, responseHandler, null);
+ }
+
+
+ // non-javadoc, see interface HttpClient
+ public <T> T execute(
+ final HttpHost target,
+ final HttpRequest request,
+ final ResponseHandler<? extends T> responseHandler,
+ final HttpContext context)
+ throws IOException, ClientProtocolException {
+ if (responseHandler == null) {
+ throw new IllegalArgumentException
+ ("Response handler must not be null.");
+ }
+
+ HttpResponse response = execute(target, request, context);
+
+ T result;
+ try {
+ result = responseHandler.handleResponse(response);
+ } catch (Throwable t) {
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ try {
+ entity.consumeContent();
+ } catch (Throwable t2) {
+ // Log this exception. The original exception is more
+ // important and will be thrown to the caller.
+ this.log.warn("Error consuming content after an exception.", t2);
+ }
+ }
+
+ if (t instanceof Error) {
+ throw (Error) t;
+ }
+
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+
+ if (t instanceof IOException) {
+ throw (IOException) t;
+ }
+
+ throw new UndeclaredThrowableException(t);
+ }
+
+ // Handling the response was successful. Ensure that the content has
+ // been fully consumed.
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ // Let this exception go to the caller.
+ entity.consumeContent();
+ }
+
+ return result;
+ }
+
+
+} // class AbstractHttpClient
diff --git a/src/org/apache/http/impl/client/BasicCookieStore.java b/src/org/apache/http/impl/client/BasicCookieStore.java
new file mode 100644
index 0000000..9970961
--- /dev/null
+++ b/src/org/apache/http/impl/client/BasicCookieStore.java
@@ -0,0 +1,162 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/BasicCookieStore.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.http.client.CookieStore;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieIdentityComparator;
+
+/**
+ * Default implementation of {@link CookieStore}
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author Rodney Waldhoff
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:adrian@intencha.com">Adrian Sutton</a>
+ *
+ * @since 4.0
+ */
+public class BasicCookieStore implements CookieStore {
+
+ private final ArrayList<Cookie> cookies;
+
+ private final Comparator<Cookie> cookieComparator;
+
+ // -------------------------------------------------------- Class Variables
+
+ /**
+ * Default constructor.
+ */
+ public BasicCookieStore() {
+ super();
+ this.cookies = new ArrayList<Cookie>();
+ this.cookieComparator = new CookieIdentityComparator();
+ }
+
+ /**
+ * Adds an {@link Cookie HTTP cookie}, replacing any existing equivalent cookies.
+ * If the given cookie has already expired it will not be added, but existing
+ * values will still be removed.
+ *
+ * @param cookie the {@link Cookie cookie} to be added
+ *
+ * @see #addCookies(Cookie[])
+ *
+ */
+ public synchronized void addCookie(Cookie cookie) {
+ if (cookie != null) {
+ // first remove any old cookie that is equivalent
+ for (Iterator<Cookie> it = cookies.iterator(); it.hasNext();) {
+ if (cookieComparator.compare(cookie, it.next()) == 0) {
+ it.remove();
+ break;
+ }
+ }
+ if (!cookie.isExpired(new Date())) {
+ cookies.add(cookie);
+ }
+ }
+ }
+
+ /**
+ * Adds an array of {@link Cookie HTTP cookies}. Cookies are added individually and
+ * in the given array order. If any of the given cookies has already expired it will
+ * not be added, but existing values will still be removed.
+ *
+ * @param cookies the {@link Cookie cookies} to be added
+ *
+ * @see #addCookie(Cookie)
+ *
+ */
+ public synchronized void addCookies(Cookie[] cookies) {
+ if (cookies != null) {
+ for (Cookie cooky : cookies) {
+ this.addCookie(cooky);
+ }
+ }
+ }
+
+ /**
+ * Returns an immutable array of {@link Cookie cookies} that this HTTP
+ * state currently contains.
+ *
+ * @return an array of {@link Cookie cookies}.
+ */
+ public synchronized List<Cookie> getCookies() {
+ return Collections.unmodifiableList(this.cookies);
+ }
+
+ /**
+ * Removes all of {@link Cookie cookies} in this HTTP state
+ * that have expired by the specified {@link java.util.Date date}.
+ *
+ * @return true if any cookies were purged.
+ *
+ * @see Cookie#isExpired(Date)
+ */
+ public synchronized boolean clearExpired(final Date date) {
+ if (date == null) {
+ return false;
+ }
+ boolean removed = false;
+ for (Iterator<Cookie> it = cookies.iterator(); it.hasNext();) {
+ if (it.next().isExpired(date)) {
+ it.remove();
+ removed = true;
+ }
+ }
+ return removed;
+ }
+
+ @Override
+ public String toString() {
+ return cookies.toString();
+ }
+
+ /**
+ * Clears all cookies.
+ */
+ public synchronized void clear() {
+ cookies.clear();
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/BasicCredentialsProvider.java b/src/org/apache/http/impl/client/BasicCredentialsProvider.java
new file mode 100644
index 0000000..02427ea
--- /dev/null
+++ b/src/org/apache/http/impl/client/BasicCredentialsProvider.java
@@ -0,0 +1,143 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.HashMap;
+
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.CredentialsProvider;
+
+/**
+ * Default implementation of {@link CredentialsProvider}
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author Rodney Waldhoff
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:adrian@intencha.com">Adrian Sutton</a>
+ *
+ * @since 4.0
+ */
+public class BasicCredentialsProvider implements CredentialsProvider {
+
+ private final HashMap<AuthScope, Credentials> credMap;
+
+ /**
+ * Default constructor.
+ */
+ public BasicCredentialsProvider() {
+ super();
+ this.credMap = new HashMap<AuthScope, Credentials>();
+ }
+
+ /**
+ * Sets the {@link Credentials credentials} for the given authentication
+ * scope. Any previous credentials for the given scope will be overwritten.
+ *
+ * @param authscope the {@link AuthScope authentication scope}
+ * @param credentials the authentication {@link Credentials credentials}
+ * for the given scope.
+ *
+ * @see #getCredentials(AuthScope)
+ */
+ public synchronized void setCredentials(
+ final AuthScope authscope,
+ final Credentials credentials) {
+ if (authscope == null) {
+ throw new IllegalArgumentException("Authentication scope may not be null");
+ }
+ credMap.put(authscope, credentials);
+ }
+
+ /**
+ * Find matching {@link Credentials credentials} for the given authentication scope.
+ *
+ * @param map the credentials hash map
+ * @param authscope the {@link AuthScope authentication scope}
+ * @return the credentials
+ *
+ */
+ private static Credentials matchCredentials(
+ final HashMap<AuthScope, Credentials> map,
+ final AuthScope authscope) {
+ // see if we get a direct hit
+ Credentials creds = map.get(authscope);
+ if (creds == null) {
+ // Nope.
+ // Do a full scan
+ int bestMatchFactor = -1;
+ AuthScope bestMatch = null;
+ for (AuthScope current: map.keySet()) {
+ int factor = authscope.match(current);
+ if (factor > bestMatchFactor) {
+ bestMatchFactor = factor;
+ bestMatch = current;
+ }
+ }
+ if (bestMatch != null) {
+ creds = map.get(bestMatch);
+ }
+ }
+ return creds;
+ }
+
+ /**
+ * Get the {@link Credentials credentials} for the given authentication scope.
+ *
+ * @param authscope the {@link AuthScope authentication scope}
+ * @return the credentials
+ *
+ * @see #setCredentials(AuthScope, Credentials)
+ */
+ public synchronized Credentials getCredentials(final AuthScope authscope) {
+ if (authscope == null) {
+ throw new IllegalArgumentException("Authentication scope may not be null");
+ }
+ return matchCredentials(this.credMap, authscope);
+ }
+
+ @Override
+ public String toString() {
+ return credMap.toString();
+ }
+
+ /**
+ * Clears all credentials.
+ */
+ public synchronized void clear() {
+ this.credMap.clear();
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/BasicResponseHandler.java b/src/org/apache/http/impl/client/BasicResponseHandler.java
new file mode 100644
index 0000000..f17d30d
--- /dev/null
+++ b/src/org/apache/http/impl/client/BasicResponseHandler.java
@@ -0,0 +1,79 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.HttpResponseException;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * A {@link ResponseHandler} that returns the response body as a String
+ * for successful (2xx) responses. If the response code was >= 300, the response
+ * body is consumed and an {@link HttpResponseException} is thrown.
+ *
+ * If this is used with
+ * {@link org.apache.http.client.HttpClient#execute(
+ * org.apache.http.client.methods.HttpUriRequest, ResponseHandler),
+ * HttpClient may handle redirects (3xx responses) internally.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 677240 $
+ *
+ * @since 4.0
+ */
+public class BasicResponseHandler implements ResponseHandler<String> {
+
+ /**
+ * Returns the response body as a String if the response was successful (a
+ * 2xx status code). If no response body exists, this returns null. If the
+ * response was unsuccessful (>= 300 status code), throws an
+ * {@link HttpResponseException}.
+ */
+ public String handleResponse(final HttpResponse response)
+ throws HttpResponseException, IOException {
+ StatusLine statusLine = response.getStatusLine();
+ if (statusLine.getStatusCode() >= 300) {
+ throw new HttpResponseException(statusLine.getStatusCode(),
+ statusLine.getReasonPhrase());
+ }
+
+ HttpEntity entity = response.getEntity();
+ return entity == null ? null : EntityUtils.toString(entity);
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/ClientParamsStack.java b/src/org/apache/http/impl/client/ClientParamsStack.java
new file mode 100644
index 0000000..a017e5d
--- /dev/null
+++ b/src/org/apache/http/impl/client/ClientParamsStack.java
@@ -0,0 +1,282 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/ClientParamsStack.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.AbstractHttpParams;
+
+
+/**
+ * Represents a stack of parameter collections.
+ * When retrieving a parameter, the stack is searched in a fixed order
+ * and the first match returned. Setting parameters via the stack is
+ * not supported. To minimize overhead, the stack has a fixed size and
+ * does not maintain an internal array.
+ * The supported stack entries, sorted by increasing priority, are:
+ * <ol>
+ * <li>Application parameters:
+ * expected to be the same for all clients used by an application.
+ * These provide "global", that is application-wide, defaults.
+ * </li>
+ * <li>Client parameters:
+ * specific to an instance of
+ * {@link org.apache.http.client.HttpClient HttpClient}.
+ * These provide client specific defaults.
+ * </li>
+ * <li>Request parameters:
+ * specific to a single request execution.
+ * For overriding client and global defaults.
+ * </li>
+ * <li>Override parameters:
+ * specific to an instance of
+ * {@link org.apache.http.client.HttpClient HttpClient}.
+ * These can be used to set parameters that cannot be overridden
+ * on a per-request basis.
+ * </li>
+ * </ol>
+ * Each stack entry may be <code>null</code>. That is preferable over
+ * an empty params collection, since it avoids searching the empty collection
+ * when looking up parameters.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * @version $Revision: 673450 $
+ */
+public class ClientParamsStack extends AbstractHttpParams {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The application parameter collection, or <code>null</code>. */
+ protected final HttpParams applicationParams;
+
+ /** The client parameter collection, or <code>null</code>. */
+ protected final HttpParams clientParams;
+
+ /** The request parameter collection, or <code>null</code>. */
+ protected final HttpParams requestParams;
+
+ /** The override parameter collection, or <code>null</code>. */
+ protected final HttpParams overrideParams;
+
+
+ /**
+ * Creates a new parameter stack from elements.
+ * The arguments will be stored as-is, there is no copying to
+ * prevent modification.
+ *
+ * @param aparams application parameters, or <code>null</code>
+ * @param cparams client parameters, or <code>null</code>
+ * @param rparams request parameters, or <code>null</code>
+ * @param oparams override parameters, or <code>null</code>
+ */
+ public ClientParamsStack(HttpParams aparams, HttpParams cparams,
+ HttpParams rparams, HttpParams oparams) {
+ applicationParams = aparams;
+ clientParams = cparams;
+ requestParams = rparams;
+ overrideParams = oparams;
+ }
+
+
+ /**
+ * Creates a copy of a parameter stack.
+ * The new stack will have the exact same entries as the argument stack.
+ * There is no copying of parameters.
+ *
+ * @param stack the stack to copy
+ */
+ public ClientParamsStack(ClientParamsStack stack) {
+ this(stack.getApplicationParams(),
+ stack.getClientParams(),
+ stack.getRequestParams(),
+ stack.getOverrideParams());
+ }
+
+
+ /**
+ * Creates a modified copy of a parameter stack.
+ * The new stack will contain the explicitly passed elements.
+ * For elements where the explicit argument is <code>null</code>,
+ * the corresponding element from the argument stack is used.
+ * There is no copying of parameters.
+ *
+ * @param stack the stack to modify
+ * @param aparams application parameters, or <code>null</code>
+ * @param cparams client parameters, or <code>null</code>
+ * @param rparams request parameters, or <code>null</code>
+ * @param oparams override parameters, or <code>null</code>
+ */
+ public ClientParamsStack(ClientParamsStack stack,
+ HttpParams aparams, HttpParams cparams,
+ HttpParams rparams, HttpParams oparams) {
+ this((aparams != null) ? aparams : stack.getApplicationParams(),
+ (cparams != null) ? cparams : stack.getClientParams(),
+ (rparams != null) ? rparams : stack.getRequestParams(),
+ (oparams != null) ? oparams : stack.getOverrideParams());
+ }
+
+
+ /**
+ * Obtains the application parameters of this stack.
+ *
+ * @return the application parameters, or <code>null</code>
+ */
+ public final HttpParams getApplicationParams() {
+ return applicationParams;
+ }
+
+ /**
+ * Obtains the client parameters of this stack.
+ *
+ * @return the client parameters, or <code>null</code>
+ */
+ public final HttpParams getClientParams() {
+ return clientParams;
+ }
+
+ /**
+ * Obtains the request parameters of this stack.
+ *
+ * @return the request parameters, or <code>null</code>
+ */
+ public final HttpParams getRequestParams() {
+ return requestParams;
+ }
+
+ /**
+ * Obtains the override parameters of this stack.
+ *
+ * @return the override parameters, or <code>null</code>
+ */
+ public final HttpParams getOverrideParams() {
+ return overrideParams;
+ }
+
+
+ /**
+ * Obtains a parameter from this stack.
+ * See class comment for search order.
+ *
+ * @param name the name of the parameter to obtain
+ *
+ * @return the highest-priority value for that parameter, or
+ * <code>null</code> if it is not set anywhere in this stack
+ */
+ public Object getParameter(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException
+ ("Parameter name must not be null.");
+ }
+
+ Object result = null;
+
+ if (overrideParams != null) {
+ result = overrideParams.getParameter(name);
+ }
+ if ((result == null) && (requestParams != null)) {
+ result = requestParams.getParameter(name);
+ }
+ if ((result == null) && (clientParams != null)) {
+ result = clientParams.getParameter(name);
+ }
+ if ((result == null) && (applicationParams != null)) {
+ result = applicationParams.getParameter(name);
+ }
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("'" + name + "': " + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Does <i>not</i> set a parameter.
+ * Parameter stacks are read-only. It is possible, though discouraged,
+ * to access and modify specific stack entries.
+ * Derived classes may change this behavior.
+ *
+ * @param name ignored
+ * @param value ignored
+ *
+ * @return nothing
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public HttpParams setParameter(String name, Object value)
+ throws UnsupportedOperationException {
+
+ throw new UnsupportedOperationException
+ ("Setting parameters in a stack is not supported.");
+ }
+
+
+ /**
+ * Does <i>not</i> remove a parameter.
+ * Parameter stacks are read-only. It is possible, though discouraged,
+ * to access and modify specific stack entries.
+ * Derived classes may change this behavior.
+ *
+ * @param name ignored
+ *
+ * @return nothing
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public boolean removeParameter(String name) {
+ throw new UnsupportedOperationException
+ ("Removing parameters in a stack is not supported.");
+ }
+
+
+ /**
+ * Does <i>not</i> copy parameters.
+ * Parameter stacks are lightweight objects, expected to be instantiated
+ * as needed and to be used only in a very specific context. On top of
+ * that, they are read-only. The typical copy operation to prevent
+ * accidental modification of parameters passed by the application to
+ * a framework object is therefore pointless and disabled.
+ * Create a new stack if you really need a copy.
+ * <br/>
+ * Derived classes may change this behavior.
+ *
+ * @return <code>this</code> parameter stack
+ */
+ public HttpParams copy() {
+ return this;
+ }
+
+
+}
diff --git a/src/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java b/src/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java
new file mode 100644
index 0000000..c7641d2
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: $
+ * $Revision: $
+ * $Date: $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.client;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.HeaderElementIterator;
+import org.apache.http.HttpResponse;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.message.BasicHeaderElementIterator;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Default implementation of a strategy deciding duration
+ * that a connection can remain idle.
+ *
+ * The default implementation looks solely at the 'Keep-Alive'
+ * header's timeout token.
+ *
+ * @author <a href="mailto:sberlin at gmail.com">Sam Berlin</a>
+ *
+ * @version $Revision: $
+ *
+ * @since 4.0
+ */
+public class DefaultConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {
+
+ public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ HeaderElementIterator it = new BasicHeaderElementIterator(
+ response.headerIterator(HTTP.CONN_KEEP_ALIVE));
+ while (it.hasNext()) {
+ HeaderElement he = it.nextElement();
+ String param = he.getName();
+ String value = he.getValue();
+ if (value != null && param.equalsIgnoreCase("timeout")) {
+ try {
+ return Long.parseLong(value) * 1000;
+ } catch(NumberFormatException ignore) {
+ }
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/DefaultHttpClient.java b/src/org/apache/http/impl/client/DefaultHttpClient.java
new file mode 100644
index 0000000..f0b694e
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultHttpClient.java
@@ -0,0 +1,332 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java $
+ * $Revision: 677250 $
+ * $Date: 2008-07-16 04:45:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpVersion;
+import org.apache.http.auth.AuthSchemeRegistry;
+import org.apache.http.client.AuthenticationHandler;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.params.AuthPolicy;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.params.CookiePolicy;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.client.protocol.RequestAddCookies;
+import org.apache.http.client.protocol.RequestDefaultHeaders;
+import org.apache.http.client.protocol.RequestProxyAuthentication;
+import org.apache.http.client.protocol.RequestTargetAuthentication;
+import org.apache.http.client.protocol.ResponseProcessCookies;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionManagerFactory;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.cookie.CookieSpecRegistry;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.auth.BasicSchemeFactory;
+import org.apache.http.impl.auth.DigestSchemeFactory;
+import org.apache.http.impl.conn.DefaultHttpRoutePlanner;
+import org.apache.http.impl.conn.SingleClientConnManager;
+import org.apache.http.impl.cookie.BestMatchSpecFactory;
+import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
+import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
+import org.apache.http.impl.cookie.RFC2109SpecFactory;
+import org.apache.http.impl.cookie.RFC2965SpecFactory;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.protocol.RequestConnControl;
+import org.apache.http.protocol.RequestContent;
+import org.apache.http.protocol.RequestExpectContinue;
+import org.apache.http.protocol.RequestTargetHost;
+import org.apache.http.protocol.RequestUserAgent;
+import org.apache.http.util.VersionInfo;
+
+
+
+/**
+ * Default implementation of an HTTP client.
+ * <br/>
+ * This class replaces <code>HttpClient</code> in HttpClient 3.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 677250 $
+ *
+ * @since 4.0
+ */
+public class DefaultHttpClient extends AbstractHttpClient {
+
+
+ /**
+ * Creates a new HTTP client from parameters and a connection manager.
+ *
+ * @param params the parameters
+ * @param conman the connection manager
+ */
+ public DefaultHttpClient(
+ final ClientConnectionManager conman,
+ final HttpParams params) {
+ super(conman, params);
+ }
+
+
+ public DefaultHttpClient(final HttpParams params) {
+ super(null, params);
+ }
+
+
+ public DefaultHttpClient() {
+ super(null, null);
+ }
+
+
+ @Override
+ protected HttpParams createHttpParams() {
+ HttpParams params = new BasicHttpParams();
+ HttpProtocolParams.setVersion(params,
+ HttpVersion.HTTP_1_1);
+ HttpProtocolParams.setContentCharset(params,
+ HTTP.DEFAULT_CONTENT_CHARSET);
+ HttpProtocolParams.setUseExpectContinue(params,
+ true);
+
+ // determine the release version from packaged version info
+ final VersionInfo vi = VersionInfo.loadVersionInfo
+ ("org.apache.http.client", getClass().getClassLoader());
+ final String release = (vi != null) ?
+ vi.getRelease() : VersionInfo.UNAVAILABLE;
+ HttpProtocolParams.setUserAgent(params,
+ "Apache-HttpClient/" + release + " (java 1.4)");
+
+ return params;
+ }
+
+
+ @Override
+ protected HttpRequestExecutor createRequestExecutor() {
+ return new HttpRequestExecutor();
+ }
+
+
+ @Override
+ protected ClientConnectionManager createClientConnectionManager() {
+ SchemeRegistry registry = new SchemeRegistry();
+ registry.register(
+ new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+ registry.register(
+ new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
+
+ ClientConnectionManager connManager = null;
+ HttpParams params = getParams();
+
+ ClientConnectionManagerFactory factory = null;
+
+ // Try first getting the factory directly as an object.
+ factory = (ClientConnectionManagerFactory) params
+ .getParameter(ClientPNames.CONNECTION_MANAGER_FACTORY);
+ if (factory == null) { // then try getting its class name.
+ String className = (String) params.getParameter(
+ ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME);
+ if (className != null) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ factory = (ClientConnectionManagerFactory) clazz.newInstance();
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalStateException("Invalid class name: " + className);
+ } catch (IllegalAccessException ex) {
+ throw new IllegalAccessError(ex.getMessage());
+ } catch (InstantiationException ex) {
+ throw new InstantiationError(ex.getMessage());
+ }
+ }
+ }
+
+ if(factory != null) {
+ connManager = factory.newInstance(params, registry);
+ } else {
+ connManager = new SingleClientConnManager(getParams(), registry);
+ }
+
+ return connManager;
+ }
+
+
+ @Override
+ protected HttpContext createHttpContext() {
+ HttpContext context = new BasicHttpContext();
+ context.setAttribute(
+ ClientContext.AUTHSCHEME_REGISTRY,
+ getAuthSchemes());
+ context.setAttribute(
+ ClientContext.COOKIESPEC_REGISTRY,
+ getCookieSpecs());
+ context.setAttribute(
+ ClientContext.COOKIE_STORE,
+ getCookieStore());
+ context.setAttribute(
+ ClientContext.CREDS_PROVIDER,
+ getCredentialsProvider());
+ return context;
+ }
+
+
+ @Override
+ protected ConnectionReuseStrategy createConnectionReuseStrategy() {
+ return new DefaultConnectionReuseStrategy();
+ }
+
+ @Override
+ protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
+ return new DefaultConnectionKeepAliveStrategy();
+ }
+
+
+ @Override
+ protected AuthSchemeRegistry createAuthSchemeRegistry() {
+ AuthSchemeRegistry registry = new AuthSchemeRegistry();
+ registry.register(
+ AuthPolicy.BASIC,
+ new BasicSchemeFactory());
+ registry.register(
+ AuthPolicy.DIGEST,
+ new DigestSchemeFactory());
+ return registry;
+ }
+
+
+ @Override
+ protected CookieSpecRegistry createCookieSpecRegistry() {
+ CookieSpecRegistry registry = new CookieSpecRegistry();
+ registry.register(
+ CookiePolicy.BEST_MATCH,
+ new BestMatchSpecFactory());
+ registry.register(
+ CookiePolicy.BROWSER_COMPATIBILITY,
+ new BrowserCompatSpecFactory());
+ registry.register(
+ CookiePolicy.NETSCAPE,
+ new NetscapeDraftSpecFactory());
+ registry.register(
+ CookiePolicy.RFC_2109,
+ new RFC2109SpecFactory());
+ registry.register(
+ CookiePolicy.RFC_2965,
+ new RFC2965SpecFactory());
+ return registry;
+ }
+
+
+ @Override
+ protected BasicHttpProcessor createHttpProcessor() {
+ BasicHttpProcessor httpproc = new BasicHttpProcessor();
+ httpproc.addInterceptor(new RequestDefaultHeaders());
+ // Required protocol interceptors
+ httpproc.addInterceptor(new RequestContent());
+ httpproc.addInterceptor(new RequestTargetHost());
+ // Recommended protocol interceptors
+ httpproc.addInterceptor(new RequestConnControl());
+ httpproc.addInterceptor(new RequestUserAgent());
+ httpproc.addInterceptor(new RequestExpectContinue());
+ // HTTP state management interceptors
+ httpproc.addInterceptor(new RequestAddCookies());
+ httpproc.addInterceptor(new ResponseProcessCookies());
+ // HTTP authentication interceptors
+ httpproc.addInterceptor(new RequestTargetAuthentication());
+ httpproc.addInterceptor(new RequestProxyAuthentication());
+ return httpproc;
+ }
+
+
+ @Override
+ protected HttpRequestRetryHandler createHttpRequestRetryHandler() {
+ return new DefaultHttpRequestRetryHandler();
+ }
+
+
+ @Override
+ protected RedirectHandler createRedirectHandler() {
+ return new DefaultRedirectHandler();
+ }
+
+
+ @Override
+ protected AuthenticationHandler createTargetAuthenticationHandler() {
+ return new DefaultTargetAuthenticationHandler();
+ }
+
+
+ @Override
+ protected AuthenticationHandler createProxyAuthenticationHandler() {
+ return new DefaultProxyAuthenticationHandler();
+ }
+
+
+ @Override
+ protected CookieStore createCookieStore() {
+ return new BasicCookieStore();
+ }
+
+
+ @Override
+ protected CredentialsProvider createCredentialsProvider() {
+ return new BasicCredentialsProvider();
+ }
+
+
+ @Override
+ protected HttpRoutePlanner createHttpRoutePlanner() {
+ return new DefaultHttpRoutePlanner
+ (getConnectionManager().getSchemeRegistry());
+ }
+
+
+ @Override
+ protected UserTokenHandler createUserTokenHandler() {
+ return new DefaultUserTokenHandler();
+ }
+
+} // class DefaultHttpClient
diff --git a/src/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java b/src/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java
new file mode 100644
index 0000000..7f66990
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java
@@ -0,0 +1,134 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java $
+ * $Revision: 652726 $
+ * $Date: 2008-05-01 18:16:51 -0700 (Thu, 01 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import org.apache.http.NoHttpResponseException;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.ExecutionContext;
+
+/**
+ * The default {@link HttpRequestRetryHandler} used by request executors.
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
+
+ /** the number of times a method will be retried */
+ private final int retryCount;
+
+ /** Whether or not methods that have successfully sent their request will be retried */
+ private final boolean requestSentRetryEnabled;
+
+ /**
+ * Default constructor
+ */
+ public DefaultHttpRequestRetryHandler(int retryCount, boolean requestSentRetryEnabled) {
+ super();
+ this.retryCount = retryCount;
+ this.requestSentRetryEnabled = requestSentRetryEnabled;
+ }
+
+ /**
+ * Default constructor
+ */
+ public DefaultHttpRequestRetryHandler() {
+ this(3, false);
+ }
+ /**
+ * Used <code>retryCount</code> and <code>requestSentRetryEnabled</code> to determine
+ * if the given method should be retried.
+ */
+ public boolean retryRequest(
+ final IOException exception,
+ int executionCount,
+ final HttpContext context) {
+ if (exception == null) {
+ throw new IllegalArgumentException("Exception parameter may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+ if (executionCount > this.retryCount) {
+ // Do not retry if over max retry count
+ return false;
+ }
+ if (exception instanceof NoHttpResponseException) {
+ // Retry if the server dropped connection on us
+ return true;
+ }
+ if (exception instanceof InterruptedIOException) {
+ // Timeout
+ return false;
+ }
+ if (exception instanceof UnknownHostException) {
+ // Unknown host
+ return false;
+ }
+ if (exception instanceof SSLHandshakeException) {
+ // SSL handshake exception
+ return false;
+ }
+ Boolean b = (Boolean)
+ context.getAttribute(ExecutionContext.HTTP_REQ_SENT);
+ boolean sent = (b != null && b.booleanValue());
+ if (!sent || this.requestSentRetryEnabled) {
+ // Retry if the request has not been sent fully or
+ // if it's OK to retry methods that have been sent
+ return true;
+ }
+ // otherwise do not retry
+ return false;
+ }
+
+ /**
+ * @return <code>true</code> if this handler will retry methods that have
+ * successfully sent their request, <code>false</code> otherwise
+ */
+ public boolean isRequestSentRetryEnabled() {
+ return requestSentRetryEnabled;
+ }
+
+ /**
+ * @return the maximum number of times a method will be retried
+ */
+ public int getRetryCount() {
+ return retryCount;
+ }
+}
diff --git a/src/org/apache/http/impl/client/DefaultProxyAuthenticationHandler.java b/src/org/apache/http/impl/client/DefaultProxyAuthenticationHandler.java
new file mode 100644
index 0000000..c188da8
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultProxyAuthenticationHandler.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultProxyAuthenticationHandler.java $
+ * $Revision: 603615 $
+ * $Date: 2007-12-12 06:03:21 -0800 (Wed, 12 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.Map;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class DefaultProxyAuthenticationHandler extends AbstractAuthenticationHandler {
+
+ public DefaultProxyAuthenticationHandler() {
+ super();
+ }
+
+ public boolean isAuthenticationRequested(
+ final HttpResponse response,
+ final HttpContext context) {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ int status = response.getStatusLine().getStatusCode();
+ return status == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED;
+ }
+
+ public Map<String, Header> getChallenges(
+ final HttpResponse response,
+ final HttpContext context) throws MalformedChallengeException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ Header[] headers = response.getHeaders(AUTH.PROXY_AUTH);
+ return parseChallenges(headers);
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/DefaultRedirectHandler.java b/src/org/apache/http/impl/client/DefaultRedirectHandler.java
new file mode 100644
index 0000000..0811b28
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultRedirectHandler.java
@@ -0,0 +1,183 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultRedirectHandler.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolException;
+import org.apache.http.client.CircularRedirectException;
+import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.utils.URIUtils;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.ExecutionContext;
+
+
+/**
+ * Default implementation of {@link RedirectHandler}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 673450 $
+ *
+ * @since 4.0
+ */
+public class DefaultRedirectHandler implements RedirectHandler {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ private static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
+
+ public DefaultRedirectHandler() {
+ super();
+ }
+
+ public boolean isRedirectRequested(
+ final HttpResponse response,
+ final HttpContext context) {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ int statusCode = response.getStatusLine().getStatusCode();
+ switch (statusCode) {
+ case HttpStatus.SC_MOVED_TEMPORARILY:
+ case HttpStatus.SC_MOVED_PERMANENTLY:
+ case HttpStatus.SC_SEE_OTHER:
+ case HttpStatus.SC_TEMPORARY_REDIRECT:
+ return true;
+ default:
+ return false;
+ } //end of switch
+ }
+
+ public URI getLocationURI(
+ final HttpResponse response,
+ final HttpContext context) throws ProtocolException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ //get the location header to find out where to redirect to
+ Header locationHeader = response.getFirstHeader("location");
+ if (locationHeader == null) {
+ // got a redirect response, but no location header
+ throw new ProtocolException(
+ "Received redirect response " + response.getStatusLine()
+ + " but no location header");
+ }
+ String location = locationHeader.getValue();
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Redirect requested to location '" + location + "'");
+ }
+
+ URI uri;
+ try {
+ uri = new URI(location);
+ } catch (URISyntaxException ex) {
+ throw new ProtocolException("Invalid redirect URI: " + location, ex);
+ }
+
+ HttpParams params = response.getParams();
+ // rfc2616 demands the location value be a complete URI
+ // Location = "Location" ":" absoluteURI
+ if (!uri.isAbsolute()) {
+ if (params.isParameterTrue(ClientPNames.REJECT_RELATIVE_REDIRECT)) {
+ throw new ProtocolException("Relative redirect location '"
+ + uri + "' not allowed");
+ }
+ // Adjust location URI
+ HttpHost target = (HttpHost) context.getAttribute(
+ ExecutionContext.HTTP_TARGET_HOST);
+ if (target == null) {
+ throw new IllegalStateException("Target host not available " +
+ "in the HTTP context");
+ }
+
+ HttpRequest request = (HttpRequest) context.getAttribute(
+ ExecutionContext.HTTP_REQUEST);
+
+ try {
+ URI requestURI = new URI(request.getRequestLine().getUri());
+ URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, true);
+ uri = URIUtils.resolve(absoluteRequestURI, uri);
+ } catch (URISyntaxException ex) {
+ throw new ProtocolException(ex.getMessage(), ex);
+ }
+ }
+
+ if (params.isParameterFalse(ClientPNames.ALLOW_CIRCULAR_REDIRECTS)) {
+
+ RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(
+ REDIRECT_LOCATIONS);
+
+ if (redirectLocations == null) {
+ redirectLocations = new RedirectLocations();
+ context.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
+ }
+
+ URI redirectURI;
+ if (uri.getFragment() != null) {
+ try {
+ HttpHost target = new HttpHost(
+ uri.getHost(),
+ uri.getPort(),
+ uri.getScheme());
+ redirectURI = URIUtils.rewriteURI(uri, target, true);
+ } catch (URISyntaxException ex) {
+ throw new ProtocolException(ex.getMessage(), ex);
+ }
+ } else {
+ redirectURI = uri;
+ }
+
+ if (redirectLocations.contains(redirectURI)) {
+ throw new CircularRedirectException("Circular redirect to '" +
+ redirectURI + "'");
+ } else {
+ redirectLocations.add(redirectURI);
+ }
+ }
+
+ return uri;
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/DefaultRequestDirector.java b/src/org/apache/http/impl/client/DefaultRequestDirector.java
new file mode 100644
index 0000000..511f8a0
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultRequestDirector.java
@@ -0,0 +1,1088 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultRequestDirector.java $
+ * $Revision: 676023 $
+ * $Date: 2008-07-11 09:40:56 -0700 (Fri, 11 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolException;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.client.AuthenticationHandler;
+import org.apache.http.client.RequestDirector;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.NonRepeatableRequestException;
+import org.apache.http.client.RedirectException;
+import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.methods.AbortableHttpRequest;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.params.HttpClientParams;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.client.utils.URIUtils;
+import org.apache.http.conn.BasicManagedEntity;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.params.ConnManagerParams;
+import org.apache.http.conn.routing.BasicRouteDirector;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.HttpRouteDirector;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestExecutor;
+
+/**
+ * Default implementation of {@link RequestDirector}.
+ * <br/>
+ * This class replaces the <code>HttpMethodDirector</code> in HttpClient 3.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 676023 $
+ *
+ * @since 4.0
+ */
+public class DefaultRequestDirector implements RequestDirector {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The connection manager. */
+ protected final ClientConnectionManager connManager;
+
+ /** The route planner. */
+ protected final HttpRoutePlanner routePlanner;
+
+ /** The connection re-use strategy. */
+ protected final ConnectionReuseStrategy reuseStrategy;
+
+ /** The keep-alive duration strategy. */
+ protected final ConnectionKeepAliveStrategy keepAliveStrategy;
+
+ /** The request executor. */
+ protected final HttpRequestExecutor requestExec;
+
+ /** The HTTP protocol processor. */
+ protected final HttpProcessor httpProcessor;
+
+ /** The request retry handler. */
+ protected final HttpRequestRetryHandler retryHandler;
+
+ /** The redirect handler. */
+ protected final RedirectHandler redirectHandler;
+
+ /** The target authentication handler. */
+ private final AuthenticationHandler targetAuthHandler;
+
+ /** The proxy authentication handler. */
+ private final AuthenticationHandler proxyAuthHandler;
+
+ /** The user token handler. */
+ private final UserTokenHandler userTokenHandler;
+
+ /** The HTTP parameters. */
+ protected final HttpParams params;
+
+ /** The currently allocated connection. */
+ protected ManagedClientConnection managedConn;
+
+ private int redirectCount;
+
+ private int maxRedirects;
+
+ private final AuthState targetAuthState;
+
+ private final AuthState proxyAuthState;
+
+ public DefaultRequestDirector(
+ final HttpRequestExecutor requestExec,
+ final ClientConnectionManager conman,
+ final ConnectionReuseStrategy reustrat,
+ final ConnectionKeepAliveStrategy kastrat,
+ final HttpRoutePlanner rouplan,
+ final HttpProcessor httpProcessor,
+ final HttpRequestRetryHandler retryHandler,
+ final RedirectHandler redirectHandler,
+ final AuthenticationHandler targetAuthHandler,
+ final AuthenticationHandler proxyAuthHandler,
+ final UserTokenHandler userTokenHandler,
+ final HttpParams params) {
+
+ if (requestExec == null) {
+ throw new IllegalArgumentException
+ ("Request executor may not be null.");
+ }
+ if (conman == null) {
+ throw new IllegalArgumentException
+ ("Client connection manager may not be null.");
+ }
+ if (reustrat == null) {
+ throw new IllegalArgumentException
+ ("Connection reuse strategy may not be null.");
+ }
+ if (kastrat == null) {
+ throw new IllegalArgumentException
+ ("Connection keep alive strategy may not be null.");
+ }
+ if (rouplan == null) {
+ throw new IllegalArgumentException
+ ("Route planner may not be null.");
+ }
+ if (httpProcessor == null) {
+ throw new IllegalArgumentException
+ ("HTTP protocol processor may not be null.");
+ }
+ if (retryHandler == null) {
+ throw new IllegalArgumentException
+ ("HTTP request retry handler may not be null.");
+ }
+ if (redirectHandler == null) {
+ throw new IllegalArgumentException
+ ("Redirect handler may not be null.");
+ }
+ if (targetAuthHandler == null) {
+ throw new IllegalArgumentException
+ ("Target authentication handler may not be null.");
+ }
+ if (proxyAuthHandler == null) {
+ throw new IllegalArgumentException
+ ("Proxy authentication handler may not be null.");
+ }
+ if (userTokenHandler == null) {
+ throw new IllegalArgumentException
+ ("User token handler may not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("HTTP parameters may not be null");
+ }
+ this.requestExec = requestExec;
+ this.connManager = conman;
+ this.reuseStrategy = reustrat;
+ this.keepAliveStrategy = kastrat;
+ this.routePlanner = rouplan;
+ this.httpProcessor = httpProcessor;
+ this.retryHandler = retryHandler;
+ this.redirectHandler = redirectHandler;
+ this.targetAuthHandler = targetAuthHandler;
+ this.proxyAuthHandler = proxyAuthHandler;
+ this.userTokenHandler = userTokenHandler;
+ this.params = params;
+
+ this.managedConn = null;
+
+ this.redirectCount = 0;
+ this.maxRedirects = this.params.getIntParameter(ClientPNames.MAX_REDIRECTS, 100);
+ this.targetAuthState = new AuthState();
+ this.proxyAuthState = new AuthState();
+ } // constructor
+
+
+ private RequestWrapper wrapRequest(
+ final HttpRequest request) throws ProtocolException {
+ if (request instanceof HttpEntityEnclosingRequest) {
+ return new EntityEnclosingRequestWrapper(
+ (HttpEntityEnclosingRequest) request);
+ } else {
+ return new RequestWrapper(
+ request);
+ }
+ }
+
+
+ protected void rewriteRequestURI(
+ final RequestWrapper request,
+ final HttpRoute route) throws ProtocolException {
+ try {
+
+ URI uri = request.getURI();
+ if (route.getProxyHost() != null && !route.isTunnelled()) {
+ // Make sure the request URI is absolute
+ if (!uri.isAbsolute()) {
+ HttpHost target = route.getTargetHost();
+ uri = URIUtils.rewriteURI(uri, target);
+ request.setURI(uri);
+ }
+ } else {
+ // Make sure the request URI is relative
+ if (uri.isAbsolute()) {
+ uri = URIUtils.rewriteURI(uri, null);
+ request.setURI(uri);
+ }
+ }
+
+ } catch (URISyntaxException ex) {
+ throw new ProtocolException("Invalid URI: " +
+ request.getRequestLine().getUri(), ex);
+ }
+ }
+
+
+ // non-javadoc, see interface ClientRequestDirector
+ public HttpResponse execute(HttpHost target, HttpRequest request,
+ HttpContext context)
+ throws HttpException, IOException {
+
+ HttpRequest orig = request;
+ RequestWrapper origWrapper = wrapRequest(orig);
+ origWrapper.setParams(params);
+ HttpRoute origRoute = determineRoute(target, origWrapper, context);
+
+ RoutedRequest roureq = new RoutedRequest(origWrapper, origRoute);
+
+ long timeout = ConnManagerParams.getTimeout(params);
+
+ int execCount = 0;
+
+ boolean reuse = false;
+ HttpResponse response = null;
+ boolean done = false;
+ try {
+ while (!done) {
+ // In this loop, the RoutedRequest may be replaced by a
+ // followup request and route. The request and route passed
+ // in the method arguments will be replaced. The original
+ // request is still available in 'orig'.
+
+ RequestWrapper wrapper = roureq.getRequest();
+ HttpRoute route = roureq.getRoute();
+
+ // See if we have a user token bound to the execution context
+ Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
+
+ // Allocate connection if needed
+ if (managedConn == null) {
+ ClientConnectionRequest connRequest = connManager.requestConnection(
+ route, userToken);
+ if (orig instanceof AbortableHttpRequest) {
+ ((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
+ }
+
+ try {
+ managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
+ } catch(InterruptedException interrupted) {
+ InterruptedIOException iox = new InterruptedIOException();
+ iox.initCause(interrupted);
+ throw iox;
+ }
+
+ if (HttpConnectionParams.isStaleCheckingEnabled(params)) {
+ // validate connection
+ this.log.debug("Stale connection check");
+ if (managedConn.isStale()) {
+ this.log.debug("Stale connection detected");
+ managedConn.close();
+ }
+ }
+ }
+
+ if (orig instanceof AbortableHttpRequest) {
+ ((AbortableHttpRequest) orig).setReleaseTrigger(managedConn);
+ }
+
+ // Reopen connection if needed
+ if (!managedConn.isOpen()) {
+ managedConn.open(route, context, params);
+ }
+
+ try {
+ establishRoute(route, context);
+ } catch (TunnelRefusedException ex) {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug(ex.getMessage());
+ }
+ response = ex.getResponse();
+ break;
+ }
+
+ // Reset headers on the request wrapper
+ wrapper.resetHeaders();
+
+ // Re-write request URI if needed
+ rewriteRequestURI(wrapper, route);
+
+ // Use virtual host if set
+ target = (HttpHost) wrapper.getParams().getParameter(
+ ClientPNames.VIRTUAL_HOST);
+
+ if (target == null) {
+ target = route.getTargetHost();
+ }
+
+ HttpHost proxy = route.getProxyHost();
+
+ // Populate the execution context
+ context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
+ target);
+ context.setAttribute(ExecutionContext.HTTP_PROXY_HOST,
+ proxy);
+ context.setAttribute(ExecutionContext.HTTP_CONNECTION,
+ managedConn);
+ context.setAttribute(ClientContext.TARGET_AUTH_STATE,
+ targetAuthState);
+ context.setAttribute(ClientContext.PROXY_AUTH_STATE,
+ proxyAuthState);
+
+ // Run request protocol interceptors
+ requestExec.preProcess(wrapper, httpProcessor, context);
+
+ context.setAttribute(ExecutionContext.HTTP_REQUEST,
+ wrapper);
+
+ boolean retrying = true;
+ while (retrying) {
+ // Increment total exec count (with redirects)
+ execCount++;
+ // Increment exec count for this particular request
+ wrapper.incrementExecCount();
+ if (wrapper.getExecCount() > 1 && !wrapper.isRepeatable()) {
+ throw new NonRepeatableRequestException("Cannot retry request " +
+ "with a non-repeatable request entity");
+ }
+
+ try {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Attempt " + execCount + " to execute request");
+ }
+ response = requestExec.execute(wrapper, managedConn, context);
+ retrying = false;
+
+ } catch (IOException ex) {
+ this.log.debug("Closing the connection.");
+ managedConn.close();
+ if (retryHandler.retryRequest(ex, execCount, context)) {
+ if (this.log.isInfoEnabled()) {
+ this.log.info("I/O exception ("+ ex.getClass().getName() +
+ ") caught when processing request: "
+ + ex.getMessage());
+ }
+ if (this.log.isDebugEnabled()) {
+ this.log.debug(ex.getMessage(), ex);
+ }
+ this.log.info("Retrying request");
+ } else {
+ throw ex;
+ }
+
+ // If we have a direct route to the target host
+ // just re-open connection and re-try the request
+ if (route.getHopCount() == 1) {
+ this.log.debug("Reopening the direct connection.");
+ managedConn.open(route, context, params);
+ } else {
+ // otherwise give up
+ retrying = false;
+ }
+
+ }
+
+ }
+
+ // Run response protocol interceptors
+ response.setParams(params);
+ requestExec.postProcess(response, httpProcessor, context);
+
+
+ // The connection is in or can be brought to a re-usable state.
+ reuse = reuseStrategy.keepAlive(response, context);
+ if(reuse) {
+ // Set the idle duration of this connection
+ long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
+ managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
+ }
+
+ RoutedRequest followup = handleResponse(roureq, response, context);
+ if (followup == null) {
+ done = true;
+ } else {
+ if (reuse) {
+ this.log.debug("Connection kept alive");
+ // Make sure the response body is fully consumed, if present
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ entity.consumeContent();
+ }
+ // entity consumed above is not an auto-release entity,
+ // need to mark the connection re-usable explicitly
+ managedConn.markReusable();
+ } else {
+ managedConn.close();
+ }
+ // check if we can use the same connection for the followup
+ if (!followup.getRoute().equals(roureq.getRoute())) {
+ releaseConnection();
+ }
+ roureq = followup;
+ }
+
+ userToken = this.userTokenHandler.getUserToken(context);
+ context.setAttribute(ClientContext.USER_TOKEN, userToken);
+ if (managedConn != null) {
+ managedConn.setState(userToken);
+ }
+ } // while not done
+
+
+ // check for entity, release connection if possible
+ if ((response == null) || (response.getEntity() == null) ||
+ !response.getEntity().isStreaming()) {
+ // connection not needed and (assumed to be) in re-usable state
+ if (reuse)
+ managedConn.markReusable();
+ releaseConnection();
+ } else {
+ // install an auto-release entity
+ HttpEntity entity = response.getEntity();
+ entity = new BasicManagedEntity(entity, managedConn, reuse);
+ response.setEntity(entity);
+ }
+
+ return response;
+
+ } catch (HttpException ex) {
+ abortConnection();
+ throw ex;
+ } catch (IOException ex) {
+ abortConnection();
+ throw ex;
+ } catch (RuntimeException ex) {
+ abortConnection();
+ throw ex;
+ }
+ } // execute
+
+ /**
+ * Returns the connection back to the connection manager
+ * and prepares for retrieving a new connection during
+ * the next request.
+ */
+ protected void releaseConnection() {
+ // Release the connection through the ManagedConnection instead of the
+ // ConnectionManager directly. This lets the connection control how
+ // it is released.
+ try {
+ managedConn.releaseConnection();
+ } catch(IOException ignored) {
+ this.log.debug("IOException releasing connection", ignored);
+ }
+ managedConn = null;
+ }
+
+ /**
+ * Determines the route for a request.
+ * Called by {@link #execute}
+ * to determine the route for either the original or a followup request.
+ *
+ * @param target the target host for the request.
+ * Implementations may accept <code>null</code>
+ * if they can still determine a route, for example
+ * to a default target or by inspecting the request.
+ * @param request the request to execute
+ * @param context the context to use for the execution,
+ * never <code>null</code>
+ *
+ * @return the route the request should take
+ *
+ * @throws HttpException in case of a problem
+ */
+ protected HttpRoute determineRoute(HttpHost target,
+ HttpRequest request,
+ HttpContext context)
+ throws HttpException {
+
+ if (target == null) {
+ target = (HttpHost) request.getParams().getParameter(
+ ClientPNames.DEFAULT_HOST);
+ }
+ if (target == null) {
+ throw new IllegalStateException
+ ("Target host must not be null, or set in parameters.");
+ }
+
+ return this.routePlanner.determineRoute(target, request, context);
+ }
+
+
+ /**
+ * Establishes the target route.
+ *
+ * @param route the route to establish
+ * @param context the context for the request execution
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ protected void establishRoute(HttpRoute route, HttpContext context)
+ throws HttpException, IOException {
+
+ //@@@ how to handle CONNECT requests for tunnelling?
+ //@@@ refuse to send external CONNECT via director? special handling?
+
+ //@@@ should the request parameters already be used below?
+ //@@@ probably yes, but they're not linked yet
+ //@@@ will linking above cause problems with linking in reqExec?
+ //@@@ probably not, because the parent is replaced
+ //@@@ just make sure we don't link parameters to themselves
+
+ HttpRouteDirector rowdy = new BasicRouteDirector();
+ int step;
+ do {
+ HttpRoute fact = managedConn.getRoute();
+ step = rowdy.nextStep(route, fact);
+
+ switch (step) {
+
+ case HttpRouteDirector.CONNECT_TARGET:
+ case HttpRouteDirector.CONNECT_PROXY:
+ managedConn.open(route, context, this.params);
+ break;
+
+ case HttpRouteDirector.TUNNEL_TARGET: {
+ boolean secure = createTunnelToTarget(route, context);
+ this.log.debug("Tunnel to target created.");
+ managedConn.tunnelTarget(secure, this.params);
+ } break;
+
+ case HttpRouteDirector.TUNNEL_PROXY: {
+ // The most simple example for this case is a proxy chain
+ // of two proxies, where P1 must be tunnelled to P2.
+ // route: Source -> P1 -> P2 -> Target (3 hops)
+ // fact: Source -> P1 -> Target (2 hops)
+ final int hop = fact.getHopCount()-1; // the hop to establish
+ boolean secure = createTunnelToProxy(route, hop, context);
+ this.log.debug("Tunnel to proxy created.");
+ managedConn.tunnelProxy(route.getHopTarget(hop),
+ secure, this.params);
+ } break;
+
+
+ case HttpRouteDirector.LAYER_PROTOCOL:
+ managedConn.layerProtocol(context, this.params);
+ break;
+
+ case HttpRouteDirector.UNREACHABLE:
+ throw new IllegalStateException
+ ("Unable to establish route." +
+ "\nplanned = " + route +
+ "\ncurrent = " + fact);
+
+ case HttpRouteDirector.COMPLETE:
+ // do nothing
+ break;
+
+ default:
+ throw new IllegalStateException
+ ("Unknown step indicator "+step+" from RouteDirector.");
+ } // switch
+
+ } while (step > HttpRouteDirector.COMPLETE);
+
+ } // establishConnection
+
+
+ /**
+ * Creates a tunnel to the target server.
+ * The connection must be established to the (last) proxy.
+ * A CONNECT request for tunnelling through the proxy will
+ * be created and sent, the response received and checked.
+ * This method does <i>not</i> update the connection with
+ * information about the tunnel, that is left to the caller.
+ *
+ * @param route the route to establish
+ * @param context the context for request execution
+ *
+ * @return <code>true</code> if the tunnelled route is secure,
+ * <code>false</code> otherwise.
+ * The implementation here always returns <code>false</code>,
+ * but derived classes may override.
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ protected boolean createTunnelToTarget(HttpRoute route,
+ HttpContext context)
+ throws HttpException, IOException {
+
+ HttpHost proxy = route.getProxyHost();
+ HttpHost target = route.getTargetHost();
+ HttpResponse response = null;
+
+ boolean done = false;
+ while (!done) {
+
+ done = true;
+
+ if (!this.managedConn.isOpen()) {
+ this.managedConn.open(route, context, this.params);
+ }
+
+ HttpRequest connect = createConnectRequest(route, context);
+
+ String agent = HttpProtocolParams.getUserAgent(params);
+ if (agent != null) {
+ connect.addHeader(HTTP.USER_AGENT, agent);
+ }
+ connect.addHeader(HTTP.TARGET_HOST, target.toHostString());
+
+ AuthScheme authScheme = this.proxyAuthState.getAuthScheme();
+ AuthScope authScope = this.proxyAuthState.getAuthScope();
+ Credentials creds = this.proxyAuthState.getCredentials();
+ if (creds != null) {
+ if (authScope != null || !authScheme.isConnectionBased()) {
+ try {
+ connect.addHeader(authScheme.authenticate(creds, connect));
+ } catch (AuthenticationException ex) {
+ if (this.log.isErrorEnabled()) {
+ this.log.error("Proxy authentication error: " + ex.getMessage());
+ }
+ }
+ }
+ }
+
+ response = requestExec.execute(connect, this.managedConn, context);
+
+ int status = response.getStatusLine().getStatusCode();
+ if (status < 200) {
+ throw new HttpException("Unexpected response to CONNECT request: " +
+ response.getStatusLine());
+ }
+
+ CredentialsProvider credsProvider = (CredentialsProvider)
+ context.getAttribute(ClientContext.CREDS_PROVIDER);
+
+ if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
+ if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
+
+ this.log.debug("Proxy requested authentication");
+ Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
+ response, context);
+ try {
+ processChallenges(
+ challenges, this.proxyAuthState, this.proxyAuthHandler,
+ response, context);
+ } catch (AuthenticationException ex) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("Authentication error: " + ex.getMessage());
+ break;
+ }
+ }
+ updateAuthState(this.proxyAuthState, proxy, credsProvider);
+
+ if (this.proxyAuthState.getCredentials() != null) {
+ done = false;
+
+ // Retry request
+ if (this.reuseStrategy.keepAlive(response, context)) {
+ this.log.debug("Connection kept alive");
+ // Consume response content
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ entity.consumeContent();
+ }
+ } else {
+ this.managedConn.close();
+ }
+
+ }
+
+ } else {
+ // Reset proxy auth scope
+ this.proxyAuthState.setAuthScope(null);
+ }
+ }
+ }
+
+ int status = response.getStatusLine().getStatusCode();
+
+ if (status > 299) {
+
+ // Buffer response content
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ response.setEntity(new BufferedHttpEntity(entity));
+ }
+
+ this.managedConn.close();
+ throw new TunnelRefusedException("CONNECT refused by proxy: " +
+ response.getStatusLine(), response);
+ }
+
+ this.managedConn.markReusable();
+
+ // How to decide on security of the tunnelled connection?
+ // The socket factory knows only about the segment to the proxy.
+ // Even if that is secure, the hop to the target may be insecure.
+ // Leave it to derived classes, consider insecure by default here.
+ return false;
+
+ } // createTunnelToTarget
+
+
+
+ /**
+ * Creates a tunnel to an intermediate proxy.
+ * This method is <i>not</i> implemented in this class.
+ * It just throws an exception here.
+ *
+ * @param route the route to establish
+ * @param hop the hop in the route to establish now.
+ * <code>route.getHopTarget(hop)</code>
+ * will return the proxy to tunnel to.
+ * @param context the context for request execution
+ *
+ * @return <code>true</code> if the partially tunnelled connection
+ * is secure, <code>false</code> otherwise.
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ protected boolean createTunnelToProxy(HttpRoute route, int hop,
+ HttpContext context)
+ throws HttpException, IOException {
+
+ // Have a look at createTunnelToTarget and replicate the parts
+ // you need in a custom derived class. If your proxies don't require
+ // authentication, it is not too hard. But for the stock version of
+ // HttpClient, we cannot make such simplifying assumptions and would
+ // have to include proxy authentication code. The HttpComponents team
+ // is currently not in a position to support rarely used code of this
+ // complexity. Feel free to submit patches that refactor the code in
+ // createTunnelToTarget to facilitate re-use for proxy tunnelling.
+
+ throw new UnsupportedOperationException
+ ("Proxy chains are not supported.");
+ }
+
+
+
+ /**
+ * Creates the CONNECT request for tunnelling.
+ * Called by {@link #createTunnelToTarget createTunnelToTarget}.
+ *
+ * @param route the route to establish
+ * @param context the context for request execution
+ *
+ * @return the CONNECT request for tunnelling
+ */
+ protected HttpRequest createConnectRequest(HttpRoute route,
+ HttpContext context) {
+ // see RFC 2817, section 5.2 and
+ // INTERNET-DRAFT: Tunneling TCP based protocols through
+ // Web proxy servers
+
+ HttpHost target = route.getTargetHost();
+
+ String host = target.getHostName();
+ int port = target.getPort();
+ if (port < 0) {
+ Scheme scheme = connManager.getSchemeRegistry().
+ getScheme(target.getSchemeName());
+ port = scheme.getDefaultPort();
+ }
+
+ StringBuilder buffer = new StringBuilder(host.length() + 6);
+ buffer.append(host);
+ buffer.append(':');
+ buffer.append(Integer.toString(port));
+
+ String authority = buffer.toString();
+ ProtocolVersion ver = HttpProtocolParams.getVersion(params);
+ HttpRequest req = new BasicHttpRequest
+ ("CONNECT", authority, ver);
+
+ return req;
+ }
+
+
+ /**
+ * Analyzes a response to check need for a followup.
+ *
+ * @param roureq the request and route.
+ * @param response the response to analayze
+ * @param context the context used for the current request execution
+ *
+ * @return the followup request and route if there is a followup, or
+ * <code>null</code> if the response should be returned as is
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ protected RoutedRequest handleResponse(RoutedRequest roureq,
+ HttpResponse response,
+ HttpContext context)
+ throws HttpException, IOException {
+
+ HttpRoute route = roureq.getRoute();
+ HttpHost proxy = route.getProxyHost();
+ RequestWrapper request = roureq.getRequest();
+
+ HttpParams params = request.getParams();
+ if (HttpClientParams.isRedirecting(params) &&
+ this.redirectHandler.isRedirectRequested(response, context)) {
+
+ if (redirectCount >= maxRedirects) {
+ throw new RedirectException("Maximum redirects ("
+ + maxRedirects + ") exceeded");
+ }
+ redirectCount++;
+
+ URI uri = this.redirectHandler.getLocationURI(response, context);
+
+ HttpHost newTarget = new HttpHost(
+ uri.getHost(),
+ uri.getPort(),
+ uri.getScheme());
+
+ HttpGet redirect = new HttpGet(uri);
+
+ HttpRequest orig = request.getOriginal();
+ redirect.setHeaders(orig.getAllHeaders());
+
+ RequestWrapper wrapper = new RequestWrapper(redirect);
+ wrapper.setParams(params);
+
+ HttpRoute newRoute = determineRoute(newTarget, wrapper, context);
+ RoutedRequest newRequest = new RoutedRequest(wrapper, newRoute);
+
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Redirecting to '" + uri + "' via " + newRoute);
+ }
+
+ return newRequest;
+ }
+
+ CredentialsProvider credsProvider = (CredentialsProvider)
+ context.getAttribute(ClientContext.CREDS_PROVIDER);
+
+ if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
+
+ if (this.targetAuthHandler.isAuthenticationRequested(response, context)) {
+
+ HttpHost target = (HttpHost)
+ context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+ if (target == null) {
+ target = route.getTargetHost();
+ }
+
+ this.log.debug("Target requested authentication");
+ Map<String, Header> challenges = this.targetAuthHandler.getChallenges(
+ response, context);
+ try {
+ processChallenges(challenges,
+ this.targetAuthState, this.targetAuthHandler,
+ response, context);
+ } catch (AuthenticationException ex) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("Authentication error: " + ex.getMessage());
+ return null;
+ }
+ }
+ updateAuthState(this.targetAuthState, target, credsProvider);
+
+ if (this.targetAuthState.getCredentials() != null) {
+ // Re-try the same request via the same route
+ return roureq;
+ } else {
+ return null;
+ }
+ } else {
+ // Reset target auth scope
+ this.targetAuthState.setAuthScope(null);
+ }
+
+ if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
+
+ this.log.debug("Proxy requested authentication");
+ Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
+ response, context);
+ try {
+ processChallenges(challenges,
+ this.proxyAuthState, this.proxyAuthHandler,
+ response, context);
+ } catch (AuthenticationException ex) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("Authentication error: " + ex.getMessage());
+ return null;
+ }
+ }
+ updateAuthState(this.proxyAuthState, proxy, credsProvider);
+
+ if (this.proxyAuthState.getCredentials() != null) {
+ // Re-try the same request via the same route
+ return roureq;
+ } else {
+ return null;
+ }
+ } else {
+ // Reset proxy auth scope
+ this.proxyAuthState.setAuthScope(null);
+ }
+ }
+ return null;
+ } // handleResponse
+
+
+ /**
+ * Shuts down the connection.
+ * This method is called from a <code>catch</code> block in
+ * {@link #execute execute} during exception handling.
+ */
+ private void abortConnection() {
+ ManagedClientConnection mcc = managedConn;
+ if (mcc != null) {
+ // we got here as the result of an exception
+ // no response will be returned, release the connection
+ managedConn = null;
+ try {
+ mcc.abortConnection();
+ } catch (IOException ex) {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug(ex.getMessage(), ex);
+ }
+ }
+ // ensure the connection manager properly releases this connection
+ try {
+ mcc.releaseConnection();
+ } catch(IOException ignored) {
+ this.log.debug("Error releasing connection", ignored);
+ }
+ }
+ } // abortConnection
+
+
+ private void processChallenges(
+ final Map<String, Header> challenges,
+ final AuthState authState,
+ final AuthenticationHandler authHandler,
+ final HttpResponse response,
+ final HttpContext context)
+ throws MalformedChallengeException, AuthenticationException {
+
+ AuthScheme authScheme = authState.getAuthScheme();
+ if (authScheme == null) {
+ // Authentication not attempted before
+ authScheme = authHandler.selectScheme(challenges, response, context);
+ authState.setAuthScheme(authScheme);
+ }
+ String id = authScheme.getSchemeName();
+
+ Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
+ if (challenge == null) {
+ throw new AuthenticationException(id +
+ " authorization challenge expected, but not found");
+ }
+ authScheme.processChallenge(challenge);
+ this.log.debug("Authorization challenge processed");
+ }
+
+
+ private void updateAuthState(
+ final AuthState authState,
+ final HttpHost host,
+ final CredentialsProvider credsProvider) {
+
+ if (!authState.isValid()) {
+ return;
+ }
+
+ String hostname = host.getHostName();
+ int port = host.getPort();
+ if (port < 0) {
+ Scheme scheme = connManager.getSchemeRegistry().getScheme(host);
+ port = scheme.getDefaultPort();
+ }
+
+ AuthScheme authScheme = authState.getAuthScheme();
+ AuthScope authScope = new AuthScope(
+ hostname,
+ port,
+ authScheme.getRealm(),
+ authScheme.getSchemeName());
+
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Authentication scope: " + authScope);
+ }
+ Credentials creds = authState.getCredentials();
+ if (creds == null) {
+ creds = credsProvider.getCredentials(authScope);
+ if (this.log.isDebugEnabled()) {
+ if (creds != null) {
+ this.log.debug("Found credentials");
+ } else {
+ this.log.debug("Credentials not found");
+ }
+ }
+ } else {
+ if (authScheme.isComplete()) {
+ this.log.debug("Authentication failed");
+ creds = null;
+ }
+ }
+ authState.setAuthScope(authScope);
+ authState.setCredentials(creds);
+ }
+
+} // class DefaultClientRequestDirector
diff --git a/src/org/apache/http/impl/client/DefaultTargetAuthenticationHandler.java b/src/org/apache/http/impl/client/DefaultTargetAuthenticationHandler.java
new file mode 100644
index 0000000..5794549
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultTargetAuthenticationHandler.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultTargetAuthenticationHandler.java $
+ * $Revision: 603615 $
+ * $Date: 2007-12-12 06:03:21 -0800 (Wed, 12 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.Map;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class DefaultTargetAuthenticationHandler extends AbstractAuthenticationHandler {
+
+ public DefaultTargetAuthenticationHandler() {
+ super();
+ }
+
+ public boolean isAuthenticationRequested(
+ final HttpResponse response,
+ final HttpContext context) {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ int status = response.getStatusLine().getStatusCode();
+ return status == HttpStatus.SC_UNAUTHORIZED;
+ }
+
+ public Map<String, Header> getChallenges(
+ final HttpResponse response,
+ final HttpContext context) throws MalformedChallengeException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ Header[] headers = response.getHeaders(AUTH.WWW_AUTH);
+ return parseChallenges(headers);
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/DefaultUserTokenHandler.java b/src/org/apache/http/impl/client/DefaultUserTokenHandler.java
new file mode 100644
index 0000000..c8a409f
--- /dev/null
+++ b/src/org/apache/http/impl/client/DefaultUserTokenHandler.java
@@ -0,0 +1,88 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java $
+ * $Revision: 659971 $
+ * $Date: 2008-05-25 05:01:22 -0700 (Sun, 25 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.security.Principal;
+
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+
+public class DefaultUserTokenHandler implements UserTokenHandler {
+
+ public Object getUserToken(final HttpContext context) {
+
+ Principal userPrincipal = null;
+
+ AuthState targetAuthState = (AuthState) context.getAttribute(
+ ClientContext.TARGET_AUTH_STATE);
+ if (targetAuthState != null) {
+ userPrincipal = getAuthPrincipal(targetAuthState);
+ if (userPrincipal == null) {
+ AuthState proxyAuthState = (AuthState) context.getAttribute(
+ ClientContext.PROXY_AUTH_STATE);
+ userPrincipal = getAuthPrincipal(proxyAuthState);
+ }
+ }
+
+ if (userPrincipal == null) {
+ ManagedClientConnection conn = (ManagedClientConnection) context.getAttribute(
+ ExecutionContext.HTTP_CONNECTION);
+ if (conn.isOpen()) {
+ SSLSession sslsession = conn.getSSLSession();
+ if (sslsession != null) {
+ userPrincipal = sslsession.getLocalPrincipal();
+ }
+ }
+ }
+
+ return userPrincipal;
+ }
+
+ private static Principal getAuthPrincipal(final AuthState authState) {
+ AuthScheme scheme = authState.getAuthScheme();
+ if (scheme != null && scheme.isComplete() && scheme.isConnectionBased()) {
+ Credentials creds = authState.getCredentials();
+ if (creds != null) {
+ return creds.getUserPrincipal();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java b/src/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java
new file mode 100644
index 0000000..05098cf
--- /dev/null
+++ b/src/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java
@@ -0,0 +1,83 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.ProtocolException;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * A wrapper class for {@link HttpEntityEnclosingRequest}s that can
+ * be used to change properties of the current request without
+ * modifying the original object.
+ * </p>
+ * This class is also capable of resetting the request headers to
+ * the state of the original request.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 674186 $
+ *
+ * @since 4.0
+ */
+public class EntityEnclosingRequestWrapper extends RequestWrapper
+ implements HttpEntityEnclosingRequest {
+
+ private HttpEntity entity;
+
+ public EntityEnclosingRequestWrapper(final HttpEntityEnclosingRequest request)
+ throws ProtocolException {
+ super(request);
+ this.entity = request.getEntity();
+ }
+
+ public HttpEntity getEntity() {
+ return this.entity;
+ }
+
+ public void setEntity(final HttpEntity entity) {
+ this.entity = entity;
+ }
+
+ public boolean expectContinue() {
+ Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
+ return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return this.entity == null || this.entity.isRepeatable();
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/RedirectLocations.java b/src/org/apache/http/impl/client/RedirectLocations.java
new file mode 100644
index 0000000..d5c47e7
--- /dev/null
+++ b/src/org/apache/http/impl/client/RedirectLocations.java
@@ -0,0 +1,71 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/RedirectLocations.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A collection of URIs that were used as redirects.
+ */
+public class RedirectLocations {
+
+ private final Set<URI> uris;
+
+ public RedirectLocations() {
+ super();
+ this.uris = new HashSet<URI>();
+ }
+
+ /**
+ * Returns true if this collection contains the given URI.
+ */
+ public boolean contains(final URI uri) {
+ return this.uris.contains(uri);
+ }
+
+ /**
+ * Adds a new URI to the list of redirects.
+ */
+ public void add(final URI uri) {
+ this.uris.add(uri);
+ }
+
+ /**
+ * Removes a URI from the list of redirects.
+ */
+ public boolean remove(final URI uri) {
+ return this.uris.remove(uri);
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/RequestWrapper.java b/src/org/apache/http/impl/client/RequestWrapper.java
new file mode 100644
index 0000000..04a641d
--- /dev/null
+++ b/src/org/apache/http/impl/client/RequestWrapper.java
@@ -0,0 +1,170 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/RequestWrapper.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.http.HttpRequest;
+import org.apache.http.ProtocolException;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.message.AbstractHttpMessage;
+import org.apache.http.message.BasicRequestLine;
+import org.apache.http.params.HttpProtocolParams;
+
+/**
+ * A wrapper class for {@link HttpRequest}s that can be used to change
+ * properties of the current request without modifying the original
+ * object.
+ * </p>
+ * This class is also capable of resetting the request headers to
+ * the state of the original request.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 674186 $
+ *
+ * @since 4.0
+ */
+public class RequestWrapper extends AbstractHttpMessage implements HttpUriRequest {
+
+ private final HttpRequest original;
+
+ private URI uri;
+ private String method;
+ private ProtocolVersion version;
+ private int execCount;
+
+ public RequestWrapper(final HttpRequest request) throws ProtocolException {
+ super();
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ this.original = request;
+ setParams(request.getParams());
+ // Make a copy of the original URI
+ if (request instanceof HttpUriRequest) {
+ this.uri = ((HttpUriRequest) request).getURI();
+ this.method = ((HttpUriRequest) request).getMethod();
+ this.version = null;
+ } else {
+ RequestLine requestLine = request.getRequestLine();
+ try {
+ this.uri = new URI(requestLine.getUri());
+ } catch (URISyntaxException ex) {
+ throw new ProtocolException("Invalid request URI: "
+ + requestLine.getUri(), ex);
+ }
+ this.method = requestLine.getMethod();
+ this.version = request.getProtocolVersion();
+ }
+ this.execCount = 0;
+ }
+
+ public void resetHeaders() {
+ // Make a copy of original headers
+ this.headergroup.clear();
+ setHeaders(this.original.getAllHeaders());
+ }
+
+ public String getMethod() {
+ return this.method;
+ }
+
+ public void setMethod(final String method) {
+ if (method == null) {
+ throw new IllegalArgumentException("Method name may not be null");
+ }
+ this.method = method;
+ }
+
+ public ProtocolVersion getProtocolVersion() {
+ if (this.version != null) {
+ return this.version;
+ } else {
+ return HttpProtocolParams.getVersion(getParams());
+ }
+ }
+
+ public void setProtocolVersion(final ProtocolVersion version) {
+ this.version = version;
+ }
+
+
+ public URI getURI() {
+ return this.uri;
+ }
+
+ public void setURI(final URI uri) {
+ this.uri = uri;
+ }
+
+ public RequestLine getRequestLine() {
+ String method = getMethod();
+ ProtocolVersion ver = getProtocolVersion();
+ String uritext = null;
+ if (uri != null) {
+ uritext = uri.toASCIIString();
+ }
+ if (uritext == null || uritext.length() == 0) {
+ uritext = "/";
+ }
+ return new BasicRequestLine(method, uritext, ver);
+ }
+
+ public void abort() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isAborted() {
+ return false;
+ }
+
+ public HttpRequest getOriginal() {
+ return this.original;
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ public int getExecCount() {
+ return this.execCount;
+ }
+
+ public void incrementExecCount() {
+ this.execCount++;
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/RoutedRequest.java b/src/org/apache/http/impl/client/RoutedRequest.java
new file mode 100644
index 0000000..954ebe5
--- /dev/null
+++ b/src/org/apache/http/impl/client/RoutedRequest.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/RoutedRequest.java $
+ * $Revision: 645846 $
+ * $Date: 2008-04-08 03:53:39 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import org.apache.http.conn.routing.HttpRoute;
+
+
+/**
+ * A request with the route along which it should be sent.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 645846 $
+ *
+ * @since 4.0
+ */
+public class RoutedRequest {
+
+ protected final RequestWrapper request;
+ protected final HttpRoute route;
+
+ /**
+ * Creates a new routed request.
+ *
+ * @param req the request
+ * @param route the route
+ */
+ public RoutedRequest(final RequestWrapper req, final HttpRoute route) {
+ super();
+ this.request = req;
+ this.route = route;
+ }
+
+ public final RequestWrapper getRequest() {
+ return request;
+ }
+
+ public final HttpRoute getRoute() {
+ return route;
+ }
+
+} // interface RoutedRequest
diff --git a/src/org/apache/http/impl/client/TunnelRefusedException.java b/src/org/apache/http/impl/client/TunnelRefusedException.java
new file mode 100644
index 0000000..601626f
--- /dev/null
+++ b/src/org/apache/http/impl/client/TunnelRefusedException.java
@@ -0,0 +1,52 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/TunnelRefusedException.java $
+ * $Revision: 537650 $
+ * $Date: 2007-05-13 12:58:22 -0700 (Sun, 13 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+
+public class TunnelRefusedException extends HttpException {
+
+ private static final long serialVersionUID = -8646722842745617323L;
+
+ private final HttpResponse response;
+
+ public TunnelRefusedException(final String message, final HttpResponse response) {
+ super(message);
+ this.response = response;
+ }
+
+ public HttpResponse getResponse() {
+ return this.response;
+ }
+
+}
diff --git a/src/org/apache/http/impl/client/package.html b/src/org/apache/http/impl/client/package.html
new file mode 100644
index 0000000..e301283
--- /dev/null
+++ b/src/org/apache/http/impl/client/package.html
@@ -0,0 +1,4 @@
+<body>
+
+</body>
+
diff --git a/src/org/apache/http/impl/conn/AbstractClientConnAdapter.java b/src/org/apache/http/impl/conn/AbstractClientConnAdapter.java
new file mode 100644
index 0000000..5cbe010
--- /dev/null
+++ b/src/org/apache/http/impl/conn/AbstractClientConnAdapter.java
@@ -0,0 +1,399 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractClientConnAdapter.java $
+ * $Revision: 672969 $
+ * $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 Jun 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.ClientConnectionManager;
+
+
+/**
+ * Abstract adapter from {@link OperatedClientConnection operated} to
+ * {@link ManagedClientConnection managed} client connections.
+ * Read and write methods are delegated to the wrapped connection.
+ * Operations affecting the connection state have to be implemented
+ * by derived classes. Operations for querying the connection state
+ * are delegated to the wrapped connection if there is one, or
+ * return a default value if there is none.
+ * <br/>
+ * This adapter tracks the checkpoints for reusable communication states,
+ * as indicated by {@link #markReusable markReusable} and queried by
+ * {@link #isMarkedReusable isMarkedReusable}.
+ * All send and receive operations will automatically clear the mark.
+ * <br/>
+ * Connection release calls are delegated to the connection manager,
+ * if there is one. {@link #abortConnection abortConnection} will
+ * clear the reusability mark first. The connection manager is
+ * expected to tolerate multiple calls to the release method.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 672969 $ $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 Jun 2008) $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractClientConnAdapter
+ implements ManagedClientConnection {
+
+ /** Thread that requested this connection. */
+ private final Thread executionThread;
+
+ /**
+ * The connection manager, if any.
+ * This attribute MUST NOT be final, so the adapter can be detached
+ * from the connection manager without keeping a hard reference there.
+ */
+ private volatile ClientConnectionManager connManager;
+
+ /** The wrapped connection. */
+ private volatile OperatedClientConnection wrappedConnection;
+
+ /** The reusability marker. */
+ private volatile boolean markedReusable;
+
+ /** True if the connection has been aborted. */
+ private volatile boolean aborted;
+
+ /** The duration this is valid for while idle (in ms). */
+ private volatile long duration;
+
+ /**
+ * Creates a new connection adapter.
+ * The adapter is initially <i>not</i>
+ * {@link #isMarkedReusable marked} as reusable.
+ *
+ * @param mgr the connection manager, or <code>null</code>
+ * @param conn the connection to wrap, or <code>null</code>
+ */
+ protected AbstractClientConnAdapter(ClientConnectionManager mgr,
+ OperatedClientConnection conn) {
+ super();
+ executionThread = Thread.currentThread();
+ connManager = mgr;
+ wrappedConnection = conn;
+ markedReusable = false;
+ aborted = false;
+ duration = Long.MAX_VALUE;
+ } // <constructor>
+
+
+ /**
+ * Detaches this adapter from the wrapped connection.
+ * This adapter becomes useless.
+ */
+ protected void detach() {
+ wrappedConnection = null;
+ connManager = null; // base class attribute
+ duration = Long.MAX_VALUE;
+ }
+
+ protected OperatedClientConnection getWrappedConnection() {
+ return wrappedConnection;
+ }
+
+ protected ClientConnectionManager getManager() {
+ return connManager;
+ }
+
+ /**
+ * Asserts that the connection has not been aborted.
+ *
+ * @throws InterruptedIOException if the connection has been aborted
+ */
+ protected final void assertNotAborted() throws InterruptedIOException {
+ if (aborted) {
+ throw new InterruptedIOException("Connection has been shut down.");
+ }
+ }
+
+ /**
+ * Asserts that there is a wrapped connection to delegate to.
+ *
+ * @throws IllegalStateException if there is no wrapped connection
+ * or connection has been aborted
+ */
+ protected final void assertValid(
+ final OperatedClientConnection wrappedConn) {
+ if (wrappedConn == null) {
+ throw new IllegalStateException("No wrapped connection.");
+ }
+ }
+
+ // non-javadoc, see interface HttpConnection
+ public boolean isOpen() {
+ OperatedClientConnection conn = getWrappedConnection();
+ if (conn == null)
+ return false;
+
+ return conn.isOpen();
+ }
+
+
+ // non-javadoc, see interface HttpConnection
+ public boolean isStale() {
+ if (aborted)
+ return true;
+ OperatedClientConnection conn = getWrappedConnection();
+ if (conn == null)
+ return true;
+
+ return conn.isStale();
+ }
+
+
+ // non-javadoc, see interface HttpConnection
+ public void setSocketTimeout(int timeout) {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ conn.setSocketTimeout(timeout);
+ }
+
+
+ // non-javadoc, see interface HttpConnection
+ public int getSocketTimeout() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.getSocketTimeout();
+ }
+
+
+ // non-javadoc, see interface HttpConnection
+ public HttpConnectionMetrics getMetrics() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.getMetrics();
+ }
+
+
+ // non-javadoc, see interface HttpClientConnection
+ public void flush()
+ throws IOException {
+
+ assertNotAborted();
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+
+ conn.flush();
+ }
+
+
+ // non-javadoc, see interface HttpClientConnection
+ public boolean isResponseAvailable(int timeout)
+ throws IOException {
+
+ assertNotAborted();
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+
+ return conn.isResponseAvailable(timeout);
+ }
+
+
+ // non-javadoc, see interface HttpClientConnection
+ public void receiveResponseEntity(HttpResponse response)
+ throws HttpException, IOException {
+
+ assertNotAborted();
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+
+ unmarkReusable();
+ conn.receiveResponseEntity(response);
+ }
+
+
+ // non-javadoc, see interface HttpClientConnection
+ public HttpResponse receiveResponseHeader()
+ throws HttpException, IOException {
+
+ assertNotAborted();
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+
+ unmarkReusable();
+ return conn.receiveResponseHeader();
+ }
+
+
+ // non-javadoc, see interface HttpClientConnection
+ public void sendRequestEntity(HttpEntityEnclosingRequest request)
+ throws HttpException, IOException {
+
+ assertNotAborted();
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+
+ unmarkReusable();
+ conn.sendRequestEntity(request);
+ }
+
+
+ // non-javadoc, see interface HttpClientConnection
+ public void sendRequestHeader(HttpRequest request)
+ throws HttpException, IOException {
+
+ assertNotAborted();
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+
+ unmarkReusable();
+ conn.sendRequestHeader(request);
+ }
+
+
+ // non-javadoc, see interface HttpInetConnection
+ public InetAddress getLocalAddress() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.getLocalAddress();
+ }
+
+ // non-javadoc, see interface HttpInetConnection
+ public int getLocalPort() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.getLocalPort();
+ }
+
+
+ // non-javadoc, see interface HttpInetConnection
+ public InetAddress getRemoteAddress() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.getRemoteAddress();
+ }
+
+ // non-javadoc, see interface HttpInetConnection
+ public int getRemotePort() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.getRemotePort();
+ }
+
+ // non-javadoc, see interface ManagedClientConnection
+ public boolean isSecure() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ return conn.isSecure();
+ }
+
+ // non-javadoc, see interface ManagedClientConnection
+ public SSLSession getSSLSession() {
+ OperatedClientConnection conn = getWrappedConnection();
+ assertValid(conn);
+ if (!isOpen())
+ return null;
+
+ SSLSession result = null;
+ Socket sock = conn.getSocket();
+ if (sock instanceof SSLSocket) {
+ result = ((SSLSocket)sock).getSession();
+ }
+ return result;
+ }
+
+ // non-javadoc, see interface ManagedClientConnection
+ public void markReusable() {
+ markedReusable = true;
+ }
+
+ // non-javadoc, see interface ManagedClientConnection
+ public void unmarkReusable() {
+ markedReusable = false;
+ }
+
+ // non-javadoc, see interface ManagedClientConnection
+ public boolean isMarkedReusable() {
+ return markedReusable;
+ }
+
+ public void setIdleDuration(long duration, TimeUnit unit) {
+ if(duration > 0) {
+ this.duration = unit.toMillis(duration);
+ } else {
+ this.duration = -1;
+ }
+ }
+
+ // non-javadoc, see interface ConnectionReleaseTrigger
+ public void releaseConnection() {
+ if (connManager != null) {
+ connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ // non-javadoc, see interface ConnectionReleaseTrigger
+ public void abortConnection() {
+ if (aborted) {
+ return;
+ }
+ aborted = true;
+ unmarkReusable();
+ try {
+ shutdown();
+ } catch (IOException ignore) {
+ }
+ // Usually #abortConnection() is expected to be called from
+ // a helper thread in order to unblock the main execution thread
+ // blocked in an I/O operation. It may be unsafe to call
+ // #releaseConnection() from the helper thread, so we have to rely
+ // on an IOException thrown by the closed socket on the main thread
+ // to trigger the release of the connection back to the
+ // connection manager.
+ //
+ // However, if this method is called from the main execution thread
+ // it should be safe to release the connection immediately. Besides,
+ // this also helps ensure the connection gets released back to the
+ // manager if #abortConnection() is called from the main execution
+ // thread while there is no blocking I/O operation.
+ if (executionThread.equals(Thread.currentThread())) {
+ releaseConnection();
+ }
+ }
+
+} // class AbstractClientConnAdapter
diff --git a/src/org/apache/http/impl/conn/AbstractPoolEntry.java b/src/org/apache/http/impl/conn/AbstractPoolEntry.java
new file mode 100644
index 0000000..0e7d95f
--- /dev/null
+++ b/src/org/apache/http/impl/conn/AbstractPoolEntry.java
@@ -0,0 +1,322 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPoolEntry.java $
+ * $Revision: 658775 $
+ * $Date: 2008-05-21 10:30:45 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+
+import java.io.IOException;
+
+import org.apache.http.HttpHost;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.RouteTracker;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.OperatedClientConnection;
+
+
+
+/**
+ * A pool entry for use by connection manager implementations.
+ * Pool entries work in conjunction with an
+ * {@link AbstractClientConnAdapter adapter}.
+ * The adapter is handed out to applications that obtain a connection.
+ * The pool entry stores the underlying connection and tracks the
+ * {@link HttpRoute route} established.
+ * The adapter delegates methods for establishing the route to
+ * it's pool entry.
+ * <br/>
+ * If the managed connections is released or revoked, the adapter
+ * gets disconnected, but the pool entry still contains the
+ * underlying connection and the established route.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 658775 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractPoolEntry {
+
+ /** The connection operator. */
+ protected final ClientConnectionOperator connOperator;
+
+ /** The underlying connection being pooled or used. */
+ protected final OperatedClientConnection connection;
+
+ /** The route for which this entry gets allocated. */
+ //@@@ currently accessed from connection manager(s) as attribute
+ //@@@ avoid that, derived classes should decide whether update is allowed
+ //@@@ SCCM: yes, TSCCM: no
+ protected volatile HttpRoute route;
+
+ /** Connection state object */
+ protected volatile Object state;
+
+ /** The tracked route, or <code>null</code> before tracking starts. */
+ protected volatile RouteTracker tracker;
+
+
+ /**
+ * Creates a new pool entry.
+ *
+ * @param connOperator the Connection Operator for this entry
+ * @param route the planned route for the connection,
+ * or <code>null</code>
+ */
+ protected AbstractPoolEntry(ClientConnectionOperator connOperator,
+ HttpRoute route) {
+ super();
+ if (connOperator == null) {
+ throw new IllegalArgumentException("Connection operator may not be null");
+ }
+ this.connOperator = connOperator;
+ this.connection = connOperator.createConnection();
+ this.route = route;
+ this.tracker = null;
+ }
+
+ /**
+ * Returns the state object associated with this pool entry.
+ *
+ * @return The state object
+ */
+ public Object getState() {
+ return state;
+ }
+
+ /**
+ * Assigns a state object to this pool entry.
+ *
+ * @param state The state object
+ */
+ public void setState(final Object state) {
+ this.state = state;
+ }
+
+ /**
+ * Opens the underlying connection.
+ *
+ * @param route the route along which to open the connection
+ * @param context the context for opening the connection
+ * @param params the parameters for opening the connection
+ *
+ * @throws IOException in case of a problem
+ */
+ public void open(HttpRoute route,
+ HttpContext context, HttpParams params)
+ throws IOException {
+
+ if (route == null) {
+ throw new IllegalArgumentException
+ ("Route must not be null.");
+ }
+ //@@@ is context allowed to be null? depends on operator?
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+ if ((this.tracker != null) && this.tracker.isConnected()) {
+ throw new IllegalStateException("Connection already open.");
+ }
+
+ // - collect the arguments
+ // - call the operator
+ // - update the tracking data
+ // In this order, we can be sure that only a successful
+ // opening of the connection will be tracked.
+
+ //@@@ verify route against planned route?
+
+ this.tracker = new RouteTracker(route);
+ final HttpHost proxy = route.getProxyHost();
+
+ connOperator.openConnection
+ (this.connection,
+ (proxy != null) ? proxy : route.getTargetHost(),
+ route.getLocalAddress(),
+ context, params);
+
+ RouteTracker localTracker = tracker; // capture volatile
+
+ // If this tracker was reset while connecting,
+ // fail early.
+ if (localTracker == null) {
+ throw new IOException("Request aborted");
+ }
+
+ if (proxy == null) {
+ localTracker.connectTarget(this.connection.isSecure());
+ } else {
+ localTracker.connectProxy(proxy, this.connection.isSecure());
+ }
+
+ } // open
+
+
+ /**
+ * Tracks tunnelling of the connection to the target.
+ * The tunnel has to be established outside by sending a CONNECT
+ * request to the (last) proxy.
+ *
+ * @param secure <code>true</code> if the tunnel should be
+ * considered secure, <code>false</code> otherwise
+ * @param params the parameters for tunnelling the connection
+ *
+ * @throws IOException in case of a problem
+ */
+ public void tunnelTarget(boolean secure, HttpParams params)
+ throws IOException {
+
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+
+ //@@@ check for proxy in planned route?
+ if ((this.tracker == null) || !this.tracker.isConnected()) {
+ throw new IllegalStateException("Connection not open.");
+ }
+ if (this.tracker.isTunnelled()) {
+ throw new IllegalStateException
+ ("Connection is already tunnelled.");
+ }
+
+ // LOG.debug?
+
+ this.connection.update(null, tracker.getTargetHost(),
+ secure, params);
+ this.tracker.tunnelTarget(secure);
+
+ } // tunnelTarget
+
+
+ /**
+ * Tracks tunnelling of the connection to a chained proxy.
+ * The tunnel has to be established outside by sending a CONNECT
+ * request to the previous proxy.
+ *
+ * @param next the proxy to which the tunnel was established.
+ * See {@link org.apache.http.conn.ManagedClientConnection#tunnelProxy
+ * ManagedClientConnection.tunnelProxy}
+ * for details.
+ * @param secure <code>true</code> if the tunnel should be
+ * considered secure, <code>false</code> otherwise
+ * @param params the parameters for tunnelling the connection
+ *
+ * @throws IOException in case of a problem
+ */
+ public void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
+ throws IOException {
+
+ if (next == null) {
+ throw new IllegalArgumentException
+ ("Next proxy must not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+
+ //@@@ check for proxy in planned route?
+ if ((this.tracker == null) || !this.tracker.isConnected()) {
+ throw new IllegalStateException("Connection not open.");
+ }
+
+ // LOG.debug?
+
+ this.connection.update(null, next, secure, params);
+ this.tracker.tunnelProxy(next, secure);
+
+ } // tunnelProxy
+
+
+ /**
+ * Layers a protocol on top of an established tunnel.
+ *
+ * @param context the context for layering
+ * @param params the parameters for layering
+ *
+ * @throws IOException in case of a problem
+ */
+ public void layerProtocol(HttpContext context, HttpParams params)
+ throws IOException {
+
+ //@@@ is context allowed to be null? depends on operator?
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+
+ if ((this.tracker == null) || !this.tracker.isConnected()) {
+ throw new IllegalStateException("Connection not open.");
+ }
+ if (!this.tracker.isTunnelled()) {
+ //@@@ allow this?
+ throw new IllegalStateException
+ ("Protocol layering without a tunnel not supported.");
+ }
+ if (this.tracker.isLayered()) {
+ throw new IllegalStateException
+ ("Multiple protocol layering not supported.");
+ }
+
+ // - collect the arguments
+ // - call the operator
+ // - update the tracking data
+ // In this order, we can be sure that only a successful
+ // layering on top of the connection will be tracked.
+
+ final HttpHost target = tracker.getTargetHost();
+
+ connOperator.updateSecureConnection(this.connection, target,
+ context, params);
+
+ this.tracker.layerProtocol(this.connection.isSecure());
+
+ } // layerProtocol
+
+
+ /**
+ * Shuts down the entry.
+ *
+ * If {@link #open(HttpRoute, HttpContext, HttpParams)} is in progress,
+ * this will cause that open to possibly throw an {@link IOException}.
+ */
+ protected void shutdownEntry() {
+ tracker = null;
+ }
+
+
+} // class AbstractPoolEntry
+
diff --git a/src/org/apache/http/impl/conn/AbstractPooledConnAdapter.java b/src/org/apache/http/impl/conn/AbstractPooledConnAdapter.java
new file mode 100644
index 0000000..2c5fd30
--- /dev/null
+++ b/src/org/apache/http/impl/conn/AbstractPooledConnAdapter.java
@@ -0,0 +1,188 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPooledConnAdapter.java $
+ * $Revision: 658775 $
+ * $Date: 2008-05-21 10:30:45 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+
+import java.io.IOException;
+
+import org.apache.http.HttpHost;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.OperatedClientConnection;
+
+
+
+/**
+ * Abstract adapter from pool {@link AbstractPoolEntry entries} to
+ * {@link org.apache.http.conn.ManagedClientConnection managed}
+ * client connections.
+ * The connection in the pool entry is used to initialize the base class.
+ * In addition, methods to establish a route are delegated to the
+ * pool entry. {@link #shutdown shutdown} and {@link #close close}
+ * will clear the tracked route in the pool entry and call the
+ * respective method of the wrapped connection.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 658775 $ $Date: 2008-05-21 10:30:45 -0700 (Wed, 21 May 2008) $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractPooledConnAdapter extends AbstractClientConnAdapter {
+
+ /** The wrapped pool entry. */
+ protected volatile AbstractPoolEntry poolEntry;
+
+
+ /**
+ * Creates a new connection adapter.
+ *
+ * @param manager the connection manager
+ * @param entry the pool entry for the connection being wrapped
+ */
+ protected AbstractPooledConnAdapter(ClientConnectionManager manager,
+ AbstractPoolEntry entry) {
+ super(manager, entry.connection);
+ this.poolEntry = entry;
+ }
+
+
+ /**
+ * Asserts that this adapter is still attached.
+ *
+ * @throws IllegalStateException
+ * if it is {@link #detach detach}ed
+ */
+ protected final void assertAttached() {
+ if (poolEntry == null) {
+ throw new IllegalStateException("Adapter is detached.");
+ }
+ }
+
+ /**
+ * Detaches this adapter from the wrapped connection.
+ * This adapter becomes useless.
+ */
+ @Override
+ protected void detach() {
+ super.detach();
+ poolEntry = null;
+ }
+
+
+ // non-javadoc, see interface ManagedHttpConnection
+ public HttpRoute getRoute() {
+
+ assertAttached();
+ return (poolEntry.tracker == null) ?
+ null : poolEntry.tracker.toRoute();
+ }
+
+ // non-javadoc, see interface ManagedHttpConnection
+ public void open(HttpRoute route,
+ HttpContext context, HttpParams params)
+ throws IOException {
+
+ assertAttached();
+ poolEntry.open(route, context, params);
+ }
+
+
+ // non-javadoc, see interface ManagedHttpConnection
+ public void tunnelTarget(boolean secure, HttpParams params)
+ throws IOException {
+
+ assertAttached();
+ poolEntry.tunnelTarget(secure, params);
+ }
+
+
+ // non-javadoc, see interface ManagedHttpConnection
+ public void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
+ throws IOException {
+
+ assertAttached();
+ poolEntry.tunnelProxy(next, secure, params);
+ }
+
+
+ // non-javadoc, see interface ManagedHttpConnection
+ public void layerProtocol(HttpContext context, HttpParams params)
+ throws IOException {
+
+ assertAttached();
+ poolEntry.layerProtocol(context, params);
+ }
+
+
+
+ // non-javadoc, see interface HttpConnection
+ public void close() throws IOException {
+ if (poolEntry != null)
+ poolEntry.shutdownEntry();
+
+ OperatedClientConnection conn = getWrappedConnection();
+ if (conn != null) {
+ conn.close();
+ }
+ }
+
+ // non-javadoc, see interface HttpConnection
+ public void shutdown() throws IOException {
+ if (poolEntry != null)
+ poolEntry.shutdownEntry();
+
+ OperatedClientConnection conn = getWrappedConnection();
+ if (conn != null) {
+ conn.shutdown();
+ }
+ }
+
+
+ // non-javadoc, see interface ManagedClientConnection
+ public Object getState() {
+ assertAttached();
+ return poolEntry.getState();
+ }
+
+
+ // non-javadoc, see interface ManagedClientConnection
+ public void setState(final Object state) {
+ assertAttached();
+ poolEntry.setState(state);
+ }
+
+
+} // class AbstractPooledConnAdapter
diff --git a/src/org/apache/http/impl/conn/DefaultClientConnection.java b/src/org/apache/http/impl/conn/DefaultClientConnection.java
new file mode 100644
index 0000000..a41f57a
--- /dev/null
+++ b/src/org/apache/http/impl/conn/DefaultClientConnection.java
@@ -0,0 +1,259 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultClientConnection.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.params.HttpParams;
+import org.apache.http.impl.SocketHttpClientConnection;
+import org.apache.http.io.HttpMessageParser;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.io.SessionOutputBuffer;
+
+import org.apache.http.conn.OperatedClientConnection;
+
+
+/**
+ * Default implementation of an operated client connection.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 673450 $ $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * @since 4.0
+ */
+public class DefaultClientConnection extends SocketHttpClientConnection
+ implements OperatedClientConnection {
+
+ private final Log log = LogFactory.getLog(getClass());
+ private final Log headerLog = LogFactory.getLog("org.apache.http.headers");
+ private final Log wireLog = LogFactory.getLog("org.apache.http.wire");
+
+ /** The unconnected socket */
+ private volatile Socket socket;
+
+ /** The target host of this connection. */
+ private HttpHost targetHost;
+
+ /** Whether this connection is secure. */
+ private boolean connSecure;
+
+ /** True if this connection was shutdown. */
+ private volatile boolean shutdown;
+
+ public DefaultClientConnection() {
+ super();
+ }
+
+
+ // non-javadoc, see interface OperatedClientConnection
+ public final HttpHost getTargetHost() {
+ return this.targetHost;
+ }
+
+
+ // non-javadoc, see interface OperatedClientConnection
+ public final boolean isSecure() {
+ return this.connSecure;
+ }
+
+
+ @Override
+ public final Socket getSocket() {
+ return this.socket;
+ }
+
+
+ public void opening(Socket sock, HttpHost target) throws IOException {
+ assertNotOpen();
+ this.socket = sock;
+ this.targetHost = target;
+
+ // Check for shutdown after assigning socket, so that
+ if (this.shutdown) {
+ sock.close(); // allow this to throw...
+ // ...but if it doesn't, explicitly throw one ourselves.
+ throw new IOException("Connection already shutdown");
+ }
+ }
+
+
+ public void openCompleted(boolean secure, HttpParams params) throws IOException {
+ assertNotOpen();
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+ this.connSecure = secure;
+ bind(this.socket, params);
+ }
+
+ /**
+ * Force-closes this connection.
+ * If the connection is still in the process of being open (the method
+ * {@link #opening opening} was already called but
+ * {@link #openCompleted openCompleted} was not), the associated
+ * socket that is being connected to a remote address will be closed.
+ * That will interrupt a thread that is blocked on connecting
+ * the socket.
+ * If the connection is not yet open, this will prevent the connection
+ * from being opened.
+ *
+ * @throws IOException in case of a problem
+ */
+ @Override
+ public void shutdown() throws IOException {
+ log.debug("Connection shut down");
+ shutdown = true;
+
+ super.shutdown();
+ Socket sock = this.socket; // copy volatile attribute
+ if (sock != null)
+ sock.close();
+
+ } // shutdown
+
+
+ @Override
+ public void close() throws IOException {
+ log.debug("Connection closed");
+ super.close();
+ }
+
+
+ @Override
+ protected SessionInputBuffer createSessionInputBuffer(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ SessionInputBuffer inbuffer = super.createSessionInputBuffer(
+ socket,
+ buffersize,
+ params);
+ if (wireLog.isDebugEnabled()) {
+ inbuffer = new LoggingSessionInputBuffer(inbuffer, new Wire(wireLog));
+ }
+ return inbuffer;
+ }
+
+
+ @Override
+ protected SessionOutputBuffer createSessionOutputBuffer(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ SessionOutputBuffer outbuffer = super.createSessionOutputBuffer(
+ socket,
+ buffersize,
+ params);
+ if (wireLog.isDebugEnabled()) {
+ outbuffer = new LoggingSessionOutputBuffer(outbuffer, new Wire(wireLog));
+ }
+ return outbuffer;
+ }
+
+
+ @Override
+ protected HttpMessageParser createResponseParser(
+ final SessionInputBuffer buffer,
+ final HttpResponseFactory responseFactory,
+ final HttpParams params) {
+ // override in derived class to specify a line parser
+ return new DefaultResponseParser
+ (buffer, null, responseFactory, params);
+ }
+
+
+ // non-javadoc, see interface OperatedClientConnection
+ public void update(Socket sock, HttpHost target,
+ boolean secure, HttpParams params)
+ throws IOException {
+
+ assertOpen();
+ if (target == null) {
+ throw new IllegalArgumentException
+ ("Target host must not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+
+ if (sock != null) {
+ this.socket = sock;
+ bind(sock, params);
+ }
+ targetHost = target;
+ connSecure = secure;
+
+ } // update
+
+
+ @Override
+ public HttpResponse receiveResponseHeader() throws HttpException, IOException {
+ HttpResponse response = super.receiveResponseHeader();
+ if (headerLog.isDebugEnabled()) {
+ headerLog.debug("<< " + response.getStatusLine().toString());
+ Header[] headers = response.getAllHeaders();
+ for (Header header : headers) {
+ headerLog.debug("<< " + header.toString());
+ }
+ }
+ return response;
+ }
+
+
+ @Override
+ public void sendRequestHeader(HttpRequest request) throws HttpException, IOException {
+ super.sendRequestHeader(request);
+ if (headerLog.isDebugEnabled()) {
+ headerLog.debug(">> " + request.getRequestLine().toString());
+ Header[] headers = request.getAllHeaders();
+ for (Header header : headers) {
+ headerLog.debug(">> " + header.toString());
+ }
+ }
+ }
+
+} // class DefaultClientConnection
diff --git a/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java b/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
new file mode 100644
index 0000000..41488e1
--- /dev/null
+++ b/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
@@ -0,0 +1,216 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionOperator.java $
+ * $Revision: 652193 $
+ * $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.Socket;
+import java.net.InetAddress;
+
+import org.apache.http.HttpHost;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.protocol.HttpContext;
+
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.scheme.LayeredSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.scheme.SocketFactory;
+
+
+/**
+ * Default implementation of a
+ * {@link ClientConnectionOperator ClientConnectionOperator}.
+ * It uses a {@link SchemeRegistry SchemeRegistry} to look up
+ * {@link SocketFactory SocketFactory} objects.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 652193 $ $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 2008) $
+ *
+ * @since 4.0
+ */
+public class DefaultClientConnectionOperator
+ implements ClientConnectionOperator {
+
+
+ /** The scheme registry for looking up socket factories. */
+ protected SchemeRegistry schemeRegistry;
+
+
+ /**
+ * Creates a new client connection operator for the given scheme registry.
+ *
+ * @param schemes the scheme registry
+ */
+ public DefaultClientConnectionOperator(SchemeRegistry schemes) {
+ if (schemes == null) {
+ throw new IllegalArgumentException
+ ("Scheme registry must not be null.");
+ }
+ schemeRegistry = schemes;
+ }
+
+
+ // non-javadoc, see interface ClientConnectionOperator
+ public OperatedClientConnection createConnection() {
+ return new DefaultClientConnection();
+ }
+
+
+ // non-javadoc, see interface ClientConnectionOperator
+ public void openConnection(OperatedClientConnection conn,
+ HttpHost target,
+ InetAddress local,
+ HttpContext context,
+ HttpParams params)
+ throws IOException {
+
+ if (conn == null) {
+ throw new IllegalArgumentException
+ ("Connection must not be null.");
+ }
+ if (target == null) {
+ throw new IllegalArgumentException
+ ("Target host must not be null.");
+ }
+ // local address may be null
+ //@@@ is context allowed to be null?
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+ if (conn.isOpen()) {
+ throw new IllegalArgumentException
+ ("Connection must not be open.");
+ }
+
+ final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
+ final SocketFactory sf = schm.getSocketFactory();
+
+ Socket sock = sf.createSocket();
+ conn.opening(sock, target);
+
+ try {
+ sock = sf.connectSocket(sock, target.getHostName(),
+ schm.resolvePort(target.getPort()),
+ local, 0, params);
+ } catch (ConnectException ex) {
+ throw new HttpHostConnectException(target, ex);
+ }
+ prepareSocket(sock, context, params);
+ conn.openCompleted(sf.isSecure(sock), params);
+ } // openConnection
+
+
+ // non-javadoc, see interface ClientConnectionOperator
+ public void updateSecureConnection(OperatedClientConnection conn,
+ HttpHost target,
+ HttpContext context,
+ HttpParams params)
+ throws IOException {
+
+
+ if (conn == null) {
+ throw new IllegalArgumentException
+ ("Connection must not be null.");
+ }
+ if (target == null) {
+ throw new IllegalArgumentException
+ ("Target host must not be null.");
+ }
+ //@@@ is context allowed to be null?
+ if (params == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+ if (!conn.isOpen()) {
+ throw new IllegalArgumentException
+ ("Connection must be open.");
+ }
+
+ final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
+ if (!(schm.getSocketFactory() instanceof LayeredSocketFactory)) {
+ throw new IllegalArgumentException
+ ("Target scheme (" + schm.getName() +
+ ") must have layered socket factory.");
+ }
+
+ final LayeredSocketFactory lsf = (LayeredSocketFactory) schm.getSocketFactory();
+ final Socket sock;
+ try {
+ sock = lsf.createSocket
+ (conn.getSocket(), target.getHostName(), target.getPort(), true);
+ } catch (ConnectException ex) {
+ throw new HttpHostConnectException(target, ex);
+ }
+ prepareSocket(sock, context, params);
+ conn.update(sock, target, lsf.isSecure(sock), params);
+ //@@@ error handling: close the layered socket in case of exception?
+
+ } // updateSecureConnection
+
+
+ /**
+ * Performs standard initializations on a newly created socket.
+ *
+ * @param sock the socket to prepare
+ * @param context the context for the connection
+ * @param params the parameters from which to prepare the socket
+ *
+ * @throws IOException in case of an IO problem
+ */
+ protected void prepareSocket(Socket sock, HttpContext context,
+ HttpParams params)
+ throws IOException {
+
+ // context currently not used, but derived classes may need it
+ //@@@ is context allowed to be null?
+
+ sock.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
+ sock.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
+
+ int linger = HttpConnectionParams.getLinger(params);
+ if (linger >= 0) {
+ sock.setSoLinger(linger > 0, linger);
+ }
+
+ } // prepareSocket
+
+
+} // class DefaultClientConnectionOperator
+
diff --git a/src/org/apache/http/impl/conn/DefaultHttpRoutePlanner.java b/src/org/apache/http/impl/conn/DefaultHttpRoutePlanner.java
new file mode 100644
index 0000000..90fd55f
--- /dev/null
+++ b/src/org/apache/http/impl/conn/DefaultHttpRoutePlanner.java
@@ -0,0 +1,121 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultHttpRoutePlanner.java $
+ * $Revision: 658785 $
+ * $Date: 2008-05-21 10:47:40 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+
+import java.net.InetAddress;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.protocol.HttpContext;
+
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+
+import org.apache.http.conn.params.ConnRouteParams;
+
+
+/**
+ * Default implementation of an {@link HttpRoutePlanner}.
+ * This implementation is based on
+ * {@link org.apache.http.conn.params.ConnRoutePNames parameters}.
+ * It will not make use of any Java system properties,
+ * nor of system or browser proxy settings.
+ */
+public class DefaultHttpRoutePlanner implements HttpRoutePlanner {
+
+ /** The scheme registry. */
+ protected SchemeRegistry schemeRegistry;
+
+
+ /**
+ * Creates a new default route planner.
+ *
+ * @param schreg the scheme registry
+ */
+ public DefaultHttpRoutePlanner(SchemeRegistry schreg) {
+ if (schreg == null) {
+ throw new IllegalArgumentException
+ ("SchemeRegistry must not be null.");
+ }
+ schemeRegistry = schreg;
+ }
+
+
+ // non-javadoc, see interface HttpRoutePlanner
+ public HttpRoute determineRoute(HttpHost target,
+ HttpRequest request,
+ HttpContext context)
+ throws HttpException {
+
+ if (request == null) {
+ throw new IllegalStateException
+ ("Request must not be null.");
+ }
+
+ // If we have a forced route, we can do without a target.
+ HttpRoute route =
+ ConnRouteParams.getForcedRoute(request.getParams());
+ if (route != null)
+ return route;
+
+ // If we get here, there is no forced route.
+ // So we need a target to compute a route.
+
+ if (target == null) {
+ throw new IllegalStateException
+ ("Target host must not be null.");
+ }
+
+ final InetAddress local =
+ ConnRouteParams.getLocalAddress(request.getParams());
+ final HttpHost proxy =
+ ConnRouteParams.getDefaultProxy(request.getParams());
+
+ final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
+ // as it is typically used for TLS/SSL, we assume that
+ // a layered scheme implies a secure connection
+ final boolean secure = schm.isLayered();
+
+ if (proxy == null) {
+ route = new HttpRoute(target, local, secure);
+ } else {
+ route = new HttpRoute(target, local, proxy, secure);
+ }
+ return route;
+ }
+
+
+}
diff --git a/src/org/apache/http/impl/conn/DefaultResponseParser.java b/src/org/apache/http/impl/conn/DefaultResponseParser.java
new file mode 100644
index 0000000..f817a10
--- /dev/null
+++ b/src/org/apache/http/impl/conn/DefaultResponseParser.java
@@ -0,0 +1,103 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultResponseParser.java $
+ * $Revision: 617638 $
+ * $Date: 2008-02-01 12:49:26 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.NoHttpResponseException;
+import org.apache.http.ProtocolException;
+import org.apache.http.StatusLine;
+import org.apache.http.conn.params.ConnConnectionPNames;
+import org.apache.http.impl.io.AbstractMessageParser;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.message.LineParser;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+public class DefaultResponseParser extends AbstractMessageParser {
+
+ private final HttpResponseFactory responseFactory;
+ private final CharArrayBuffer lineBuf;
+ private final int maxGarbageLines;
+
+ public DefaultResponseParser(
+ final SessionInputBuffer buffer,
+ final LineParser parser,
+ final HttpResponseFactory responseFactory,
+ final HttpParams params) {
+ super(buffer, parser, params);
+ if (responseFactory == null) {
+ throw new IllegalArgumentException
+ ("Response factory may not be null");
+ }
+ this.responseFactory = responseFactory;
+ this.lineBuf = new CharArrayBuffer(128);
+ this.maxGarbageLines = params.getIntParameter(
+ ConnConnectionPNames.MAX_STATUS_LINE_GARBAGE, Integer.MAX_VALUE);
+ }
+
+
+ @Override
+ protected HttpMessage parseHead(
+ final SessionInputBuffer sessionBuffer) throws IOException, HttpException {
+ // clear the buffer
+ this.lineBuf.clear();
+ //read out the HTTP status string
+ int count = 0;
+ ParserCursor cursor = null;
+ do {
+ int i = sessionBuffer.readLine(this.lineBuf);
+ if (i == -1 && count == 0) {
+ // The server just dropped connection on us
+ throw new NoHttpResponseException("The target server failed to respond");
+ }
+ cursor = new ParserCursor(0, this.lineBuf.length());
+ if (lineParser.hasProtocolVersion(this.lineBuf, cursor)) {
+ // Got one
+ break;
+ } else if (i == -1 || count >= this.maxGarbageLines) {
+ // Giving up
+ throw new ProtocolException("The server failed to respond with a " +
+ "valid HTTP response");
+ }
+ count++;
+ } while(true);
+ //create the status line from the status string
+ StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor);
+ return this.responseFactory.newHttpResponse(statusline, null);
+ }
+
+}
diff --git a/src/org/apache/http/impl/conn/IdleConnectionHandler.java b/src/org/apache/http/impl/conn/IdleConnectionHandler.java
new file mode 100644
index 0000000..2cacda3
--- /dev/null
+++ b/src/org/apache/http/impl/conn/IdleConnectionHandler.java
@@ -0,0 +1,190 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/IdleConnectionHandler.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpConnection;
+
+
+/**
+ * A helper class for connection managers to track idle connections.
+ *
+ * <p>This class is not synchronized.</p>
+ *
+ * @see org.apache.http.conn.ClientConnectionManager#closeIdleConnections
+ *
+ * @since 4.0
+ */
+public class IdleConnectionHandler {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** Holds connections and the time they were added. */
+ private final Map<HttpConnection,TimeValues> connectionToTimes;
+
+
+ public IdleConnectionHandler() {
+ super();
+ connectionToTimes = new HashMap<HttpConnection,TimeValues>();
+ }
+
+ /**
+ * Registers the given connection with this handler. The connection will be held until
+ * {@link #remove} or {@link #closeIdleConnections} is called.
+ *
+ * @param connection the connection to add
+ *
+ * @see #remove
+ */
+ public void add(HttpConnection connection, long validDuration, TimeUnit unit) {
+
+ Long timeAdded = Long.valueOf(System.currentTimeMillis());
+
+ if (log.isDebugEnabled()) {
+ log.debug("Adding connection at: " + timeAdded);
+ }
+
+ connectionToTimes.put(connection, new TimeValues(timeAdded, validDuration, unit));
+ }
+
+ /**
+ * Removes the given connection from the list of connections to be closed when idle.
+ * This will return true if the connection is still valid, and false
+ * if the connection should be considered expired and not used.
+ *
+ * @param connection
+ * @return True if the connection is still valid.
+ */
+ public boolean remove(HttpConnection connection) {
+ TimeValues times = connectionToTimes.remove(connection);
+ if(times == null) {
+ log.warn("Removing a connection that never existed!");
+ return true;
+ } else {
+ return System.currentTimeMillis() <= times.timeExpires;
+ }
+ }
+
+ /**
+ * Removes all connections referenced by this handler.
+ */
+ public void removeAll() {
+ this.connectionToTimes.clear();
+ }
+
+ /**
+ * Closes connections that have been idle for at least the given amount of time.
+ *
+ * @param idleTime the minimum idle time, in milliseconds, for connections to be closed
+ */
+ //@@@ add TimeUnit argument here?
+ public void closeIdleConnections(long idleTime) {
+
+ // the latest time for which connections will be closed
+ long idleTimeout = System.currentTimeMillis() - idleTime;
+
+ if (log.isDebugEnabled()) {
+ log.debug("Checking for connections, idleTimeout: " + idleTimeout);
+ }
+
+ Iterator<HttpConnection> connectionIter =
+ connectionToTimes.keySet().iterator();
+
+ while (connectionIter.hasNext()) {
+ HttpConnection conn = connectionIter.next();
+ TimeValues times = connectionToTimes.get(conn);
+ Long connectionTime = times.timeAdded;
+ if (connectionTime.longValue() <= idleTimeout) {
+ if (log.isDebugEnabled()) {
+ log.debug("Closing connection, connection time: " + connectionTime);
+ }
+ connectionIter.remove();
+ try {
+ conn.close();
+ } catch (IOException ex) {
+ log.debug("I/O error closing connection", ex);
+ }
+ }
+ }
+ }
+
+
+ public void closeExpiredConnections() {
+ long now = System.currentTimeMillis();
+ if (log.isDebugEnabled()) {
+ log.debug("Checking for expired connections, now: " + now);
+ }
+
+ Iterator<HttpConnection> connectionIter =
+ connectionToTimes.keySet().iterator();
+
+ while (connectionIter.hasNext()) {
+ HttpConnection conn = connectionIter.next();
+ TimeValues times = connectionToTimes.get(conn);
+ if(times.timeExpires <= now) {
+ if (log.isDebugEnabled()) {
+ log.debug("Closing connection, expired @: " + times.timeExpires);
+ }
+ connectionIter.remove();
+ try {
+ conn.close();
+ } catch (IOException ex) {
+ log.debug("I/O error closing connection", ex);
+ }
+ }
+ }
+ }
+
+ private static class TimeValues {
+ private final long timeAdded;
+ private final long timeExpires;
+
+ /**
+ * @param now The current time in milliseconds
+ * @param validDuration The duration this connection is valid for
+ * @param validUnit The unit of time the duration is specified in.
+ */
+ TimeValues(long now, long validDuration, TimeUnit validUnit) {
+ this.timeAdded = now;
+ if(validDuration > 0) {
+ this.timeExpires = now + validUnit.toMillis(validDuration);
+ } else {
+ this.timeExpires = Long.MAX_VALUE;
+ }
+ }
+ }
+}
diff --git a/src/org/apache/http/impl/conn/LoggingSessionInputBuffer.java b/src/org/apache/http/impl/conn/LoggingSessionInputBuffer.java
new file mode 100644
index 0000000..4f6477e
--- /dev/null
+++ b/src/org/apache/http/impl/conn/LoggingSessionInputBuffer.java
@@ -0,0 +1,117 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/LoggingSessionInputBuffer.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+
+import org.apache.http.io.HttpTransportMetrics;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Logs all data read to the wire LOG.
+ *
+ * @author Ortwin Glueck
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class LoggingSessionInputBuffer implements SessionInputBuffer {
+
+ /** Original session input buffer. */
+ private final SessionInputBuffer in;
+
+ /** The wire log to use for writing. */
+ private final Wire wire;
+
+ /**
+ * Create an instance that wraps the specified session input buffer.
+ * @param in The session input buffer.
+ * @param wire The wire log to use.
+ */
+ public LoggingSessionInputBuffer(final SessionInputBuffer in, final Wire wire) {
+ super();
+ this.in = in;
+ this.wire = wire;
+ }
+
+ public boolean isDataAvailable(int timeout) throws IOException {
+ return this.in.isDataAvailable(timeout);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ int l = this.in.read(b, off, len);
+ if (this.wire.enabled() && l > 0) {
+ this.wire.input(b, off, l);
+ }
+ return l;
+ }
+
+ public int read() throws IOException {
+ int l = this.in.read();
+ if (this.wire.enabled() && l > 0) {
+ this.wire.input(l);
+ }
+ return l;
+ }
+
+ public int read(byte[] b) throws IOException {
+ int l = this.in.read(b);
+ if (this.wire.enabled() && l > 0) {
+ this.wire.input(b, 0, l);
+ }
+ return l;
+ }
+
+ public String readLine() throws IOException {
+ String s = this.in.readLine();
+ if (this.wire.enabled() && s != null) {
+ this.wire.input(s + "[EOL]");
+ }
+ return s;
+ }
+
+ public int readLine(final CharArrayBuffer buffer) throws IOException {
+ int l = this.in.readLine(buffer);
+ if (this.wire.enabled() && l > 0) {
+ int pos = buffer.length() - l;
+ String s = new String(buffer.buffer(), pos, l);
+ this.wire.input(s + "[EOL]");
+ }
+ return l;
+ }
+
+ public HttpTransportMetrics getMetrics() {
+ return this.in.getMetrics();
+ }
+
+}
diff --git a/src/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java b/src/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java
new file mode 100644
index 0000000..1afab7d
--- /dev/null
+++ b/src/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java
@@ -0,0 +1,109 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+
+import org.apache.http.io.HttpTransportMetrics;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Logs all data written to the wire LOG.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class LoggingSessionOutputBuffer implements SessionOutputBuffer {
+
+ /** Original data transmitter. */
+ private final SessionOutputBuffer out;
+
+ /** The wire log to use. */
+ private final Wire wire;
+
+ /**
+ * Create an instance that wraps the specified session output buffer.
+ * @param out The session output buffer.
+ * @param wire The Wire log to use.
+ */
+ public LoggingSessionOutputBuffer(final SessionOutputBuffer out, final Wire wire) {
+ super();
+ this.out = out;
+ this.wire = wire;
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ this.out.write(b, off, len);
+ if (this.wire.enabled()) {
+ this.wire.output(b, off, len);
+ }
+ }
+
+ public void write(int b) throws IOException {
+ this.out.write(b);
+ if (this.wire.enabled()) {
+ this.wire.output(b);
+ }
+ }
+
+ public void write(byte[] b) throws IOException {
+ this.out.write(b);
+ if (this.wire.enabled()) {
+ this.wire.output(b);
+ }
+ }
+
+ public void flush() throws IOException {
+ this.out.flush();
+ }
+
+ public void writeLine(final CharArrayBuffer buffer) throws IOException {
+ this.out.writeLine(buffer);
+ if (this.wire.enabled()) {
+ String s = new String(buffer.buffer(), 0, buffer.length());
+ this.wire.output(s + "[EOL]");
+ }
+ }
+
+ public void writeLine(final String s) throws IOException {
+ this.out.writeLine(s);
+ if (this.wire.enabled()) {
+ this.wire.output(s + "[EOL]");
+ }
+ }
+
+ public HttpTransportMetrics getMetrics() {
+ return this.out.getMetrics();
+ }
+
+}
diff --git a/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java b/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
new file mode 100644
index 0000000..136caf4
--- /dev/null
+++ b/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
@@ -0,0 +1,290 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java $
+ * $Revision: 658785 $
+ * $Date: 2008-05-21 10:47:40 -0700 (Wed, 21 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.protocol.HttpContext;
+
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+
+import org.apache.http.conn.params.ConnRouteParams;
+
+
+/**
+ * Default implementation of an {@link HttpRoutePlanner}.
+ * This implementation is based on {@link java.net.ProxySelector}.
+ * By default, it will pick up the proxy settings of the JVM, either
+ * from system properties or from the browser running the application.
+ * Additionally, it interprets some
+ * {@link org.apache.http.conn.params.ConnRoutePNames parameters},
+ * though not the {@link
+ * org.apache.http.conn.params.ConnRoutePNames#DEFAULT_PROXY DEFAULT_PROXY}.
+ */
+public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
+
+ /** The scheme registry. */
+ protected SchemeRegistry schemeRegistry;
+
+ /** The proxy selector to use, or <code>null</code> for system default. */
+ protected ProxySelector proxySelector;
+
+
+ /**
+ * Creates a new proxy selector route planner.
+ *
+ * @param schreg the scheme registry
+ * @param prosel the proxy selector, or
+ * <code>null</code> for the system default
+ */
+ public ProxySelectorRoutePlanner(SchemeRegistry schreg,
+ ProxySelector prosel) {
+
+ if (schreg == null) {
+ throw new IllegalArgumentException
+ ("SchemeRegistry must not be null.");
+ }
+ schemeRegistry = schreg;
+ proxySelector = prosel;
+ }
+
+
+ /**
+ * Obtains the proxy selector to use.
+ *
+ * @return the proxy selector, or <code>null</code> for the system default
+ */
+ public ProxySelector getProxySelector() {
+ return this.proxySelector;
+ }
+
+
+ /**
+ * Sets the proxy selector to use.
+ *
+ * @param prosel the proxy selector, or
+ * <code>null</code> to use the system default
+ */
+ public void setProxySelector(ProxySelector prosel) {
+ this.proxySelector = prosel;
+ }
+
+
+
+ // non-javadoc, see interface HttpRoutePlanner
+ public HttpRoute determineRoute(HttpHost target,
+ HttpRequest request,
+ HttpContext context)
+ throws HttpException {
+
+ if (request == null) {
+ throw new IllegalStateException
+ ("Request must not be null.");
+ }
+
+ // If we have a forced route, we can do without a target.
+ HttpRoute route =
+ ConnRouteParams.getForcedRoute(request.getParams());
+ if (route != null)
+ return route;
+
+ // If we get here, there is no forced route.
+ // So we need a target to compute a route.
+
+ if (target == null) {
+ throw new IllegalStateException
+ ("Target host must not be null.");
+ }
+
+ final InetAddress local =
+ ConnRouteParams.getLocalAddress(request.getParams());
+ final HttpHost proxy = determineProxy(target, request, context);
+
+ final Scheme schm =
+ this.schemeRegistry.getScheme(target.getSchemeName());
+ // as it is typically used for TLS/SSL, we assume that
+ // a layered scheme implies a secure connection
+ final boolean secure = schm.isLayered();
+
+ if (proxy == null) {
+ route = new HttpRoute(target, local, secure);
+ } else {
+ route = new HttpRoute(target, local, proxy, secure);
+ }
+ return route;
+ }
+
+
+ /**
+ * Determines a proxy for the given target.
+ *
+ * @param target the planned target, never <code>null</code>
+ * @param request the request to be sent, never <code>null</code>
+ * @param context the context, or <code>null</code>
+ *
+ * @return the proxy to use, or <code>null</code> for a direct route
+ *
+ * @throws HttpException
+ * in case of system proxy settings that cannot be handled
+ */
+ protected HttpHost determineProxy(HttpHost target,
+ HttpRequest request,
+ HttpContext context)
+ throws HttpException {
+
+ // the proxy selector can be 'unset', so we better deal with null here
+ ProxySelector psel = this.proxySelector;
+ if (psel == null)
+ psel = ProxySelector.getDefault();
+ if (psel == null)
+ return null;
+
+ URI targetURI = null;
+ try {
+ targetURI = new URI(target.toURI());
+ } catch (URISyntaxException usx) {
+ throw new HttpException
+ ("Cannot convert host to URI: " + target, usx);
+ }
+ List<Proxy> proxies = psel.select(targetURI);
+
+ Proxy p = chooseProxy(proxies, target, request, context);
+
+ HttpHost result = null;
+ if (p.type() == Proxy.Type.HTTP) {
+ // convert the socket address to an HttpHost
+ if (!(p.address() instanceof InetSocketAddress)) {
+ throw new HttpException
+ ("Unable to handle non-Inet proxy address: "+p.address());
+ }
+ final InetSocketAddress isa = (InetSocketAddress) p.address();
+ // assume default scheme (http)
+ result = new HttpHost(getHost(isa), isa.getPort());
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Obtains a host from an {@link InetSocketAddress}.
+ *
+ * @param isa the socket address
+ *
+ * @return a host string, either as a symbolic name or
+ * as a literal IP address string
+ * <br/>
+ * (TODO: determine format for IPv6 addresses, with or without [brackets])
+ */
+ protected String getHost(InetSocketAddress isa) {
+
+ //@@@ Will this work with literal IPv6 addresses, or do we
+ //@@@ need to wrap these in [] for the string representation?
+ //@@@ Having it in this method at least allows for easy workarounds.
+ return isa.isUnresolved() ?
+ isa.getHostName() : isa.getAddress().getHostAddress();
+
+ }
+
+
+ /*
+ * Chooses a proxy from a list of available proxies.
+ * The default implementation just picks the first non-SOCKS proxy
+ * from the list. If there are only SOCKS proxies,
+ * {@link Proxy#NO_PROXY Proxy.NO_PROXY} is returned.
+ * Derived classes may implement more advanced strategies,
+ * such as proxy rotation if there are multiple options.
+ *
+ * @param proxies the list of proxies to choose from,
+ * never <code>null</code> or empty
+ * @param target the planned target, never <code>null</code>
+ * @param request the request to be sent, never <code>null</code>
+ * @param context the context, or <code>null</code>
+ *
+ * @return a proxy of type {@link Proxy.Type#DIRECT DIRECT}
+ * or {@link Proxy.Type#HTTP HTTP}, never <code>null</code>
+ */
+ protected Proxy chooseProxy(List<Proxy> proxies,
+ HttpHost target,
+ HttpRequest request,
+ HttpContext context) {
+
+ if ((proxies == null) || proxies.isEmpty()) {
+ throw new IllegalArgumentException
+ ("Proxy list must not be empty.");
+ }
+
+ Proxy result = null;
+
+ // check the list for one we can use
+ for (int i=0; (result == null) && (i < proxies.size()); i++) {
+
+ Proxy p = proxies.get(i);
+ switch (p.type()) {
+
+ case DIRECT:
+ case HTTP:
+ result = p;
+ break;
+
+ case SOCKS:
+ // SOCKS hosts are not handled on the route level.
+ // The socket may make use of the SOCKS host though.
+ break;
+ }
+ }
+
+ if (result == null) {
+ //@@@ log as warning or info that only a socks proxy is available?
+ // result can only be null if all proxies are socks proxies
+ // socks proxies are not handled on the route planning level
+ result = Proxy.NO_PROXY;
+ }
+
+ return result;
+ }
+
+} // class ProxySelectorRoutePlanner
+
diff --git a/src/org/apache/http/impl/conn/SingleClientConnManager.java b/src/org/apache/http/impl/conn/SingleClientConnManager.java
new file mode 100644
index 0000000..7999f3e
--- /dev/null
+++ b/src/org/apache/http/impl/conn/SingleClientConnManager.java
@@ -0,0 +1,444 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/SingleClientConnManager.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.RouteTracker;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.params.HttpParams;
+
+
+/**
+ * A connection "manager" for a single connection.
+ * This manager is good only for single-threaded use.
+ * Allocation <i>always</i> returns the connection immediately,
+ * even if it has not been released after the previous allocation.
+ * In that case, a {@link #MISUSE_MESSAGE warning} is logged
+ * and the previously issued connection is revoked.
+ * <p>
+ * This class is derived from <code>SimpleHttpConnectionManager</code>
+ * in HttpClient 3. See there for original authors.
+ * </p>
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 673450 $
+ *
+ * @since 4.0
+ */
+public class SingleClientConnManager implements ClientConnectionManager {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The message to be logged on multiple allocation. */
+ public final static String MISUSE_MESSAGE =
+ "Invalid use of SingleClientConnManager: connection still allocated.\n" +
+ "Make sure to release the connection before allocating another one.";
+
+
+ /** The schemes supported by this connection manager. */
+ protected SchemeRegistry schemeRegistry;
+
+ /** The operator for opening and updating connections. */
+ protected ClientConnectionOperator connOperator;
+
+ /** The one and only entry in this pool. */
+ protected PoolEntry uniquePoolEntry;
+
+ /** The currently issued managed connection, if any. */
+ protected ConnAdapter managedConn;
+
+ /** The time of the last connection release, or -1. */
+ protected long lastReleaseTime;
+
+ /** The time the last released connection expires and shouldn't be reused. */
+ protected long connectionExpiresTime;
+
+ /** Whether the connection should be shut down on release. */
+ protected boolean alwaysShutDown;
+
+ /** Indicates whether this connection manager is shut down. */
+ protected volatile boolean isShutDown;
+
+
+
+
+ /**
+ * Creates a new simple connection manager.
+ *
+ * @param params the parameters for this manager
+ * @param schreg the scheme registry, or
+ * <code>null</code> for the default registry
+ */
+ public SingleClientConnManager(HttpParams params,
+ SchemeRegistry schreg) {
+
+ if (schreg == null) {
+ throw new IllegalArgumentException
+ ("Scheme registry must not be null.");
+ }
+ this.schemeRegistry = schreg;
+ this.connOperator = createConnectionOperator(schreg);
+ this.uniquePoolEntry = new PoolEntry();
+ this.managedConn = null;
+ this.lastReleaseTime = -1L;
+ this.alwaysShutDown = false; //@@@ from params? as argument?
+ this.isShutDown = false;
+
+ } // <constructor>
+
+
+ @Override
+ protected void finalize() throws Throwable {
+ shutdown();
+ super.finalize();
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public SchemeRegistry getSchemeRegistry() {
+ return this.schemeRegistry;
+ }
+
+
+ /**
+ * Hook for creating the connection operator.
+ * It is called by the constructor.
+ * Derived classes can override this method to change the
+ * instantiation of the operator.
+ * The default implementation here instantiates
+ * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
+ *
+ * @param schreg the scheme registry to use, or <code>null</code>
+ *
+ * @return the connection operator to use
+ */
+ protected ClientConnectionOperator
+ createConnectionOperator(SchemeRegistry schreg) {
+
+ return new DefaultClientConnectionOperator(schreg);
+ }
+
+
+ /**
+ * Asserts that this manager is not shut down.
+ *
+ * @throws IllegalStateException if this manager is shut down
+ */
+ protected final void assertStillUp()
+ throws IllegalStateException {
+
+ if (this.isShutDown)
+ throw new IllegalStateException("Manager is shut down.");
+ }
+
+
+ public final ClientConnectionRequest requestConnection(
+ final HttpRoute route,
+ final Object state) {
+
+ return new ClientConnectionRequest() {
+
+ public void abortRequest() {
+ // Nothing to abort, since requests are immediate.
+ }
+
+ public ManagedClientConnection getConnection(
+ long timeout, TimeUnit tunit) {
+ return SingleClientConnManager.this.getConnection(
+ route, state);
+ }
+
+ };
+ }
+
+
+ /**
+ * Obtains a connection.
+ * This method does not block.
+ *
+ * @param route where the connection should point to
+ *
+ * @return a connection that can be used to communicate
+ * along the given route
+ */
+ public ManagedClientConnection getConnection(HttpRoute route, Object state) {
+
+ if (route == null) {
+ throw new IllegalArgumentException("Route may not be null.");
+ }
+ assertStillUp();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Get connection for route " + route);
+ }
+
+ if (managedConn != null)
+ revokeConnection();
+
+ // check re-usability of the connection
+ boolean recreate = false;
+ boolean shutdown = false;
+
+ // Kill the connection if it expired.
+ closeExpiredConnections();
+
+ if (uniquePoolEntry.connection.isOpen()) {
+ RouteTracker tracker = uniquePoolEntry.tracker;
+ shutdown = (tracker == null || // can happen if method is aborted
+ !tracker.toRoute().equals(route));
+ } else {
+ // If the connection is not open, create a new PoolEntry,
+ // as the connection may have been marked not reusable,
+ // due to aborts -- and the PoolEntry should not be reused
+ // either. There's no harm in recreating an entry if
+ // the connection is closed.
+ recreate = true;
+ }
+
+ if (shutdown) {
+ recreate = true;
+ try {
+ uniquePoolEntry.shutdown();
+ } catch (IOException iox) {
+ log.debug("Problem shutting down connection.", iox);
+ }
+ }
+
+ if (recreate)
+ uniquePoolEntry = new PoolEntry();
+
+ managedConn = new ConnAdapter(uniquePoolEntry, route);
+
+ return managedConn;
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
+ assertStillUp();
+
+ if (!(conn instanceof ConnAdapter)) {
+ throw new IllegalArgumentException
+ ("Connection class mismatch, " +
+ "connection not obtained from this manager.");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Releasing connection " + conn);
+ }
+
+ ConnAdapter sca = (ConnAdapter) conn;
+ if (sca.poolEntry == null)
+ return; // already released
+ ClientConnectionManager manager = sca.getManager();
+ if (manager != null && manager != this) {
+ throw new IllegalArgumentException
+ ("Connection not obtained from this manager.");
+ }
+
+ try {
+ // make sure that the response has been read completely
+ if (sca.isOpen() && (this.alwaysShutDown ||
+ !sca.isMarkedReusable())
+ ) {
+ if (log.isDebugEnabled()) {
+ log.debug
+ ("Released connection open but not reusable.");
+ }
+
+ // make sure this connection will not be re-used
+ // we might have gotten here because of a shutdown trigger
+ // shutdown of the adapter also clears the tracked route
+ sca.shutdown();
+ }
+ } catch (IOException iox) {
+ //@@@ log as warning? let pass?
+ if (log.isDebugEnabled())
+ log.debug("Exception shutting down released connection.",
+ iox);
+ } finally {
+ sca.detach();
+ managedConn = null;
+ lastReleaseTime = System.currentTimeMillis();
+ if(validDuration > 0)
+ connectionExpiresTime = timeUnit.toMillis(validDuration) + lastReleaseTime;
+ else
+ connectionExpiresTime = Long.MAX_VALUE;
+ }
+ } // releaseConnection
+
+ public void closeExpiredConnections() {
+ if(System.currentTimeMillis() >= connectionExpiresTime) {
+ closeIdleConnections(0, TimeUnit.MILLISECONDS);
+ }
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public void closeIdleConnections(long idletime, TimeUnit tunit) {
+ assertStillUp();
+
+ // idletime can be 0 or negative, no problem there
+ if (tunit == null) {
+ throw new IllegalArgumentException("Time unit must not be null.");
+ }
+
+ if ((managedConn == null) && uniquePoolEntry.connection.isOpen()) {
+ final long cutoff =
+ System.currentTimeMillis() - tunit.toMillis(idletime);
+ if (lastReleaseTime <= cutoff) {
+ try {
+ uniquePoolEntry.close();
+ } catch (IOException iox) {
+ // ignore
+ log.debug("Problem closing idle connection.", iox);
+ }
+ }
+ }
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public void shutdown() {
+
+ this.isShutDown = true;
+
+ if (managedConn != null)
+ managedConn.detach();
+
+ try {
+ if (uniquePoolEntry != null) // and connection open?
+ uniquePoolEntry.shutdown();
+ } catch (IOException iox) {
+ // ignore
+ log.debug("Problem while shutting down manager.", iox);
+ } finally {
+ uniquePoolEntry = null;
+ }
+ }
+
+
+ /**
+ * Revokes the currently issued connection.
+ * The adapter gets disconnected, the connection will be shut down.
+ */
+ protected void revokeConnection() {
+ if (managedConn == null)
+ return;
+
+ log.warn(MISUSE_MESSAGE);
+
+ managedConn.detach();
+
+ try {
+ uniquePoolEntry.shutdown();
+ } catch (IOException iox) {
+ // ignore
+ log.debug("Problem while shutting down connection.", iox);
+ }
+ }
+
+
+ /**
+ * The pool entry for this connection manager.
+ */
+ protected class PoolEntry extends AbstractPoolEntry {
+
+ /**
+ * Creates a new pool entry.
+ *
+ */
+ protected PoolEntry() {
+ super(SingleClientConnManager.this.connOperator, null);
+ }
+
+ /**
+ * Closes the connection in this pool entry.
+ */
+ protected void close()
+ throws IOException {
+
+ shutdownEntry();
+ if (connection.isOpen())
+ connection.close();
+ }
+
+
+ /**
+ * Shuts down the connection in this pool entry.
+ */
+ protected void shutdown()
+ throws IOException {
+
+ shutdownEntry();
+ if (connection.isOpen())
+ connection.shutdown();
+ }
+
+ } // class PoolEntry
+
+
+
+ /**
+ * The connection adapter used by this manager.
+ */
+ protected class ConnAdapter extends AbstractPooledConnAdapter {
+
+ /**
+ * Creates a new connection adapter.
+ *
+ * @param entry the pool entry for the connection being wrapped
+ * @param route the planned route for this connection
+ */
+ protected ConnAdapter(PoolEntry entry, HttpRoute route) {
+ super(SingleClientConnManager.this, entry);
+ markReusable();
+ entry.route = route;
+ }
+
+ }
+
+
+} // class SingleClientConnManager
diff --git a/src/org/apache/http/impl/conn/Wire.java b/src/org/apache/http/impl/conn/Wire.java
new file mode 100644
index 0000000..147b7f5
--- /dev/null
+++ b/src/org/apache/http/impl/conn/Wire.java
@@ -0,0 +1,160 @@
+/*
+ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/Wire.java,v 1.9 2004/06/24 21:39:52 mbecke Exp $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import org.apache.commons.logging.Log;
+
+/**
+ * Logs data to the wire LOG.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class Wire {
+
+ private final Log log;
+
+ public Wire(Log log) {
+ this.log = log;
+ }
+
+ private void wire(String header, InputStream instream)
+ throws IOException {
+ StringBuilder buffer = new StringBuilder();
+ int ch;
+ while ((ch = instream.read()) != -1) {
+ if (ch == 13) {
+ buffer.append("[\\r]");
+ } else if (ch == 10) {
+ buffer.append("[\\n]\"");
+ buffer.insert(0, "\"");
+ buffer.insert(0, header);
+ log.debug(buffer.toString());
+ buffer.setLength(0);
+ } else if ((ch < 32) || (ch > 127)) {
+ buffer.append("[0x");
+ buffer.append(Integer.toHexString(ch));
+ buffer.append("]");
+ } else {
+ buffer.append((char) ch);
+ }
+ }
+ if (buffer.length() > 0) {
+ buffer.append('\"');
+ buffer.insert(0, '\"');
+ buffer.insert(0, header);
+ log.debug(buffer.toString());
+ }
+ }
+
+
+ public boolean enabled() {
+ return log.isDebugEnabled();
+ }
+
+ public void output(InputStream outstream)
+ throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output may not be null");
+ }
+ wire(">> ", outstream);
+ }
+
+ public void input(InputStream instream)
+ throws IOException {
+ if (instream == null) {
+ throw new IllegalArgumentException("Input may not be null");
+ }
+ wire("<< ", instream);
+ }
+
+ public void output(byte[] b, int off, int len)
+ throws IOException {
+ if (b == null) {
+ throw new IllegalArgumentException("Output may not be null");
+ }
+ wire(">> ", new ByteArrayInputStream(b, off, len));
+ }
+
+ public void input(byte[] b, int off, int len)
+ throws IOException {
+ if (b == null) {
+ throw new IllegalArgumentException("Input may not be null");
+ }
+ wire("<< ", new ByteArrayInputStream(b, off, len));
+ }
+
+ public void output(byte[] b)
+ throws IOException {
+ if (b == null) {
+ throw new IllegalArgumentException("Output may not be null");
+ }
+ wire(">> ", new ByteArrayInputStream(b));
+ }
+
+ public void input(byte[] b)
+ throws IOException {
+ if (b == null) {
+ throw new IllegalArgumentException("Input may not be null");
+ }
+ wire("<< ", new ByteArrayInputStream(b));
+ }
+
+ public void output(int b)
+ throws IOException {
+ output(new byte[] {(byte) b});
+ }
+
+ public void input(int b)
+ throws IOException {
+ input(new byte[] {(byte) b});
+ }
+
+ public void output(final String s)
+ throws IOException {
+ if (s == null) {
+ throw new IllegalArgumentException("Output may not be null");
+ }
+ output(s.getBytes());
+ }
+
+ public void input(final String s)
+ throws IOException {
+ if (s == null) {
+ throw new IllegalArgumentException("Input may not be null");
+ }
+ input(s.getBytes());
+ }
+}
diff --git a/src/org/apache/http/impl/conn/package.html b/src/org/apache/http/impl/conn/package.html
new file mode 100644
index 0000000..54eb3c2
--- /dev/null
+++ b/src/org/apache/http/impl/conn/package.html
@@ -0,0 +1,5 @@
+<body>
+
+
+</body>
+
diff --git a/src/org/apache/http/impl/conn/tsccm/AbstractConnPool.java b/src/org/apache/http/impl/conn/tsccm/AbstractConnPool.java
new file mode 100644
index 0000000..2b37d72
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/AbstractConnPool.java
@@ -0,0 +1,332 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/AbstractConnPool.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.conn.IdleConnectionHandler;
+
+
+/**
+ * An abstract connection pool.
+ * It is used by the {@link ThreadSafeClientConnManager}.
+ * The abstract pool includes a {@link #poolLock}, which is used to
+ * synchronize access to the internal pool datastructures.
+ * Don't use <code>synchronized</code> for that purpose!
+ */
+public abstract class AbstractConnPool implements RefQueueHandler {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /**
+ * The global lock for this pool.
+ */
+ protected final Lock poolLock;
+
+
+ /**
+ * References to issued connections.
+ * Objects in this set are of class
+ * {@link BasicPoolEntryRef BasicPoolEntryRef},
+ * and point to the pool entry for the issued connection.
+ * GCed connections are detected by the missing pool entries.
+ */
+ protected Set<BasicPoolEntryRef> issuedConnections;
+
+ /** The handler for idle connections. */
+ protected IdleConnectionHandler idleConnHandler;
+
+ /** The current total number of connections. */
+ protected int numConnections;
+
+ /**
+ * A reference queue to track loss of pool entries to GC.
+ * The same queue is used to track loss of the connection manager,
+ * so we cannot specialize the type.
+ */
+ protected ReferenceQueue<Object> refQueue;
+
+ /** A worker (thread) to track loss of pool entries to GC. */
+ private RefQueueWorker refWorker;
+
+
+ /** Indicates whether this pool is shut down. */
+ protected volatile boolean isShutDown;
+
+ /**
+ * Creates a new connection pool.
+ */
+ protected AbstractConnPool() {
+ issuedConnections = new HashSet<BasicPoolEntryRef>();
+ idleConnHandler = new IdleConnectionHandler();
+
+ boolean fair = false; //@@@ check parameters to decide
+ poolLock = new ReentrantLock(fair);
+ }
+
+
+ /**
+ * Enables connection garbage collection (GC).
+ * This method must be called immediately after creating the
+ * connection pool. It is not possible to enable connection GC
+ * after pool entries have been created. Neither is it possible
+ * to disable connection GC.
+ *
+ * @throws IllegalStateException
+ * if connection GC is already enabled, or if it cannot be
+ * enabled because there already are pool entries
+ */
+ public void enableConnectionGC()
+ throws IllegalStateException {
+
+ if (refQueue != null) {
+ throw new IllegalStateException("Connection GC already enabled.");
+ }
+ poolLock.lock();
+ try {
+ if (numConnections > 0) { //@@@ is this check sufficient?
+ throw new IllegalStateException("Pool already in use.");
+ }
+ } finally {
+ poolLock.unlock();
+ }
+
+ refQueue = new ReferenceQueue<Object>();
+ refWorker = new RefQueueWorker(refQueue, this);
+ Thread t = new Thread(refWorker); //@@@ use a thread factory
+ t.setDaemon(true);
+ t.setName("RefQueueWorker@" + this);
+ t.start();
+ }
+
+
+ /**
+ * Obtains a pool entry with a connection within the given timeout.
+ *
+ * @param route the route for which to get the connection
+ * @param timeout the timeout, 0 or negative for no timeout
+ * @param tunit the unit for the <code>timeout</code>,
+ * may be <code>null</code> only if there is no timeout
+ *
+ * @return pool entry holding a connection for the route
+ *
+ * @throws ConnectionPoolTimeoutException
+ * if the timeout expired
+ * @throws InterruptedException
+ * if the calling thread was interrupted
+ */
+ public final
+ BasicPoolEntry getEntry(
+ HttpRoute route,
+ Object state,
+ long timeout,
+ TimeUnit tunit)
+ throws ConnectionPoolTimeoutException, InterruptedException {
+ return requestPoolEntry(route, state).getPoolEntry(timeout, tunit);
+ }
+
+ /**
+ * Returns a new {@link PoolEntryRequest}, from which a {@link BasicPoolEntry}
+ * can be obtained, or the request can be aborted.
+ */
+ public abstract PoolEntryRequest requestPoolEntry(HttpRoute route, Object state);
+
+
+ /**
+ * Returns an entry into the pool.
+ * The connection of the entry is expected to be in a suitable state,
+ * either open and re-usable, or closed. The pool will not make any
+ * attempt to determine whether it can be re-used or not.
+ *
+ * @param entry the entry for the connection to release
+ * @param reusable <code>true</code> if the entry is deemed
+ * reusable, <code>false</code> otherwise.
+ * @param validDuration The duration that the entry should remain free and reusable.
+ * @param timeUnit The unit of time the duration is measured in.
+ */
+ public abstract void freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit)
+ ;
+
+
+
+ // non-javadoc, see interface RefQueueHandler
+// BEGIN android-changed
+ public void handleReference(Reference ref) {
+// END android-changed
+ poolLock.lock();
+ try {
+
+ if (ref instanceof BasicPoolEntryRef) {
+ // check if the GCed pool entry was still in use
+ //@@@ find a way to detect this without lookup
+ //@@@ flag in the BasicPoolEntryRef, to be reset when freed?
+ final boolean lost = issuedConnections.remove(ref);
+ if (lost) {
+ final HttpRoute route =
+ ((BasicPoolEntryRef)ref).getRoute();
+ if (log.isDebugEnabled()) {
+ log.debug("Connection garbage collected. " + route);
+ }
+ handleLostEntry(route);
+ }
+ }
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ /**
+ * Handles cleaning up for a lost pool entry with the given route.
+ * A lost pool entry corresponds to a connection that was
+ * garbage collected instead of being properly released.
+ *
+ * @param route the route of the pool entry that was lost
+ */
+ protected abstract void handleLostEntry(HttpRoute route)
+ ;
+
+
+ /**
+ * Closes idle connections.
+ *
+ * @param idletime the time the connections should have been idle
+ * in order to be closed now
+ * @param tunit the unit for the <code>idletime</code>
+ */
+ public void closeIdleConnections(long idletime, TimeUnit tunit) {
+
+ // idletime can be 0 or negative, no problem there
+ if (tunit == null) {
+ throw new IllegalArgumentException("Time unit must not be null.");
+ }
+
+ poolLock.lock();
+ try {
+ idleConnHandler.closeIdleConnections(tunit.toMillis(idletime));
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+ public void closeExpiredConnections() {
+ poolLock.lock();
+ try {
+ idleConnHandler.closeExpiredConnections();
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ //@@@ revise this cleanup stuff (closeIdle+deleteClosed), it's not good
+
+ /**
+ * Deletes all entries for closed connections.
+ */
+ public abstract void deleteClosedConnections()
+ ;
+
+
+ /**
+ * Shuts down this pool and all associated resources.
+ * Overriding methods MUST call the implementation here!
+ */
+ public void shutdown() {
+
+ poolLock.lock();
+ try {
+
+ if (isShutDown)
+ return;
+
+ // no point in monitoring GC anymore
+ if (refWorker != null)
+ refWorker.shutdown();
+
+ // close all connections that are issued to an application
+ Iterator<BasicPoolEntryRef> iter = issuedConnections.iterator();
+ while (iter.hasNext()) {
+ BasicPoolEntryRef per = iter.next();
+ iter.remove();
+ BasicPoolEntry entry = per.get();
+ if (entry != null) {
+ closeConnection(entry.getConnection());
+ }
+ }
+
+ // remove all references to connections
+ //@@@ use this for shutting them down instead?
+ idleConnHandler.removeAll();
+
+ isShutDown = true;
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ /**
+ * Closes a connection from this pool.
+ *
+ * @param conn the connection to close, or <code>null</code>
+ */
+ protected void closeConnection(final OperatedClientConnection conn) {
+ if (conn != null) {
+ try {
+ conn.close();
+ } catch (IOException ex) {
+ log.debug("I/O error closing connection", ex);
+ }
+ }
+ }
+
+
+
+
+
+} // class AbstractConnPool
+
diff --git a/src/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java b/src/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java
new file mode 100644
index 0000000..dded360
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java
@@ -0,0 +1,88 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java $
+ * $Revision: 652721 $
+ * $Date: 2008-05-01 17:32:20 -0700 (Thu, 01 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+
+import java.lang.ref.ReferenceQueue;
+
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.conn.AbstractPoolEntry;
+
+
+
+/**
+ * Basic implementation of a connection pool entry.
+ */
+public class BasicPoolEntry extends AbstractPoolEntry {
+
+ /**
+ * A weak reference to <code>this</code> used to detect GC of entries.
+ * Pool entries can only be GCed when they are allocated by an application
+ * and therefore not referenced with a hard link in the manager.
+ */
+ private final BasicPoolEntryRef reference;
+
+ /**
+ * Creates a new pool entry.
+ *
+ * @param op the connection operator
+ * @param route the planned route for the connection
+ * @param queue the reference queue for tracking GC of this entry,
+ * or <code>null</code>
+ */
+ public BasicPoolEntry(ClientConnectionOperator op,
+ HttpRoute route,
+ ReferenceQueue<Object> queue) {
+ super(op, route);
+ if (route == null) {
+ throw new IllegalArgumentException("HTTP route may not be null");
+ }
+ this.reference = new BasicPoolEntryRef(this, queue);
+ }
+
+ protected final OperatedClientConnection getConnection() {
+ return super.connection;
+ }
+
+ protected final HttpRoute getPlannedRoute() {
+ return super.route;
+ }
+
+ protected final BasicPoolEntryRef getWeakRef() {
+ return this.reference;
+ }
+
+
+} // class BasicPoolEntry
+
+
diff --git a/src/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java b/src/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java
new file mode 100644
index 0000000..32df8a5
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java
@@ -0,0 +1,80 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java $
+ * $Revision: 674186 $
+ * $Date: 2008-07-05 05:18:54 -0700 (Sat, 05 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+
+import org.apache.http.conn.routing.HttpRoute;
+
+
+
+/**
+ * A weak reference to a {@link BasicPoolEntry BasicPoolEntry}.
+ * This reference explicitly keeps the planned route, so the connection
+ * can be reclaimed if it is lost to garbage collection.
+ */
+public class BasicPoolEntryRef extends WeakReference<BasicPoolEntry> {
+
+ /** The planned route of the entry. */
+ private final HttpRoute route;
+
+
+ /**
+ * Creates a new reference to a pool entry.
+ *
+ * @param entry the pool entry, must not be <code>null</code>
+ * @param queue the reference queue, or <code>null</code>
+ */
+ public BasicPoolEntryRef(BasicPoolEntry entry,
+ ReferenceQueue<Object> queue) {
+ super(entry, queue);
+ if (entry == null) {
+ throw new IllegalArgumentException
+ ("Pool entry must not be null.");
+ }
+ route = entry.getPlannedRoute();
+ }
+
+
+ /**
+ * Obtain the planned route for the referenced entry.
+ * The planned route is still available, even if the entry is gone.
+ *
+ * @return the planned route
+ */
+ public final HttpRoute getRoute() {
+ return this.route;
+ }
+
+} // class BasicPoolEntryRef
+
diff --git a/src/org/apache/http/impl/conn/tsccm/BasicPooledConnAdapter.java b/src/org/apache/http/impl/conn/tsccm/BasicPooledConnAdapter.java
new file mode 100644
index 0000000..29455d0
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/BasicPooledConnAdapter.java
@@ -0,0 +1,83 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/BasicPooledConnAdapter.java $
+ * $Revision: 653214 $
+ * $Date: 2008-05-04 07:12:13 -0700 (Sun, 04 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.impl.conn.AbstractPoolEntry;
+import org.apache.http.impl.conn.AbstractPooledConnAdapter;
+
+
+
+/**
+ * A connection wrapper and callback handler.
+ * All connections given out by the manager are wrappers which
+ * can be {@link #detach detach}ed to prevent further use on release.
+ */
+public class BasicPooledConnAdapter extends AbstractPooledConnAdapter {
+
+ /**
+ * Creates a new adapter.
+ *
+ * @param tsccm the connection manager
+ * @param entry the pool entry for the connection being wrapped
+ */
+ protected BasicPooledConnAdapter(ThreadSafeClientConnManager tsccm,
+ AbstractPoolEntry entry) {
+ super(tsccm, entry);
+ markReusable();
+ }
+
+
+ @Override
+ protected ClientConnectionManager getManager() {
+ // override needed only to make method visible in this package
+ return super.getManager();
+ }
+
+
+ /**
+ * Obtains the pool entry.
+ *
+ * @return the pool entry, or <code>null</code> if detached
+ */
+ protected AbstractPoolEntry getPoolEntry() {
+ return super.poolEntry;
+ }
+
+
+ // non-javadoc, see base class
+ @Override
+ protected void detach() {
+ // override needed only to make method visible in this package
+ super.detach();
+ }
+}
diff --git a/src/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java b/src/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
new file mode 100644
index 0000000..cf59129
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
@@ -0,0 +1,698 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Queue;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.params.ConnPerRoute;
+import org.apache.http.conn.params.ConnManagerParams;
+import org.apache.http.params.HttpParams;
+
+
+/**
+ * A connection pool that maintains connections by route.
+ * This class is derived from <code>MultiThreadedHttpConnectionManager</code>
+ * in HttpClient 3.x, see there for original authors. It implements the same
+ * algorithm for connection re-use and connection-per-host enforcement:
+ * <ul>
+ * <li>connections are re-used only for the exact same route</li>
+ * <li>connection limits are enforced per route rather than per host</li>
+ * </ul>
+ * Note that access to the pool datastructures is synchronized via the
+ * {@link AbstractConnPool#poolLock poolLock} in the base class,
+ * not via <code>synchronized</code> methods.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ * @author and others
+ */
+public class ConnPoolByRoute extends AbstractConnPool {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** Connection operator for this pool */
+ protected final ClientConnectionOperator operator;
+
+ /** The list of free connections */
+ protected Queue<BasicPoolEntry> freeConnections;
+
+ /** The list of WaitingThreads waiting for a connection */
+ protected Queue<WaitingThread> waitingThreads;
+
+ /**
+ * A map of route-specific pools.
+ * Keys are of class {@link HttpRoute},
+ * values of class {@link RouteSpecificPool}.
+ */
+ protected final Map<HttpRoute, RouteSpecificPool> routeToPool;
+
+ protected final int maxTotalConnections;
+
+ private final ConnPerRoute connPerRoute;
+
+ /**
+ * Creates a new connection pool, managed by route.
+ */
+ public ConnPoolByRoute(final ClientConnectionOperator operator, final HttpParams params) {
+ super();
+ if (operator == null) {
+ throw new IllegalArgumentException("Connection operator may not be null");
+ }
+ this.operator = operator;
+
+ freeConnections = createFreeConnQueue();
+ waitingThreads = createWaitingThreadQueue();
+ routeToPool = createRouteToPoolMap();
+ maxTotalConnections = ConnManagerParams
+ .getMaxTotalConnections(params);
+ connPerRoute = ConnManagerParams
+ .getMaxConnectionsPerRoute(params);
+ }
+
+
+ /**
+ * Creates the queue for {@link #freeConnections}.
+ * Called once by the constructor.
+ *
+ * @return a queue
+ */
+ protected Queue<BasicPoolEntry> createFreeConnQueue() {
+ return new LinkedList<BasicPoolEntry>();
+ }
+
+ /**
+ * Creates the queue for {@link #waitingThreads}.
+ * Called once by the constructor.
+ *
+ * @return a queue
+ */
+ protected Queue<WaitingThread> createWaitingThreadQueue() {
+ return new LinkedList<WaitingThread>();
+ }
+
+ /**
+ * Creates the map for {@link #routeToPool}.
+ * Called once by the constructor.
+ *
+ * @return a map
+ */
+ protected Map<HttpRoute, RouteSpecificPool> createRouteToPoolMap() {
+ return new HashMap<HttpRoute, RouteSpecificPool>();
+ }
+
+
+ /**
+ * Creates a new route-specific pool.
+ * Called by {@link #getRoutePool} when necessary.
+ *
+ * @param route the route
+ *
+ * @return the new pool
+ */
+ protected RouteSpecificPool newRouteSpecificPool(HttpRoute route) {
+ return new RouteSpecificPool(route, connPerRoute.getMaxForRoute(route));
+ }
+
+
+ /**
+ * Creates a new waiting thread.
+ * Called by {@link #getRoutePool} when necessary.
+ *
+ * @param cond the condition to wait for
+ * @param rospl the route specific pool, or <code>null</code>
+ *
+ * @return a waiting thread representation
+ */
+ protected WaitingThread newWaitingThread(Condition cond,
+ RouteSpecificPool rospl) {
+ return new WaitingThread(cond, rospl);
+ }
+
+
+ /**
+ * Get a route-specific pool of available connections.
+ *
+ * @param route the route
+ * @param create whether to create the pool if it doesn't exist
+ *
+ * @return the pool for the argument route,
+ * never <code>null</code> if <code>create</code> is <code>true</code>
+ */
+ protected RouteSpecificPool getRoutePool(HttpRoute route,
+ boolean create) {
+ RouteSpecificPool rospl = null;
+ poolLock.lock();
+ try {
+
+ rospl = routeToPool.get(route);
+ if ((rospl == null) && create) {
+ // no pool for this route yet (or anymore)
+ rospl = newRouteSpecificPool(route);
+ routeToPool.put(route, rospl);
+ }
+
+ } finally {
+ poolLock.unlock();
+ }
+
+ return rospl;
+ }
+
+
+ //@@@ consider alternatives for gathering statistics
+ public int getConnectionsInPool(HttpRoute route) {
+
+ poolLock.lock();
+ try {
+ // don't allow a pool to be created here!
+ RouteSpecificPool rospl = getRoutePool(route, false);
+ return (rospl != null) ? rospl.getEntryCount() : 0;
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+ @Override
+ public PoolEntryRequest requestPoolEntry(
+ final HttpRoute route,
+ final Object state) {
+
+ final WaitingThreadAborter aborter = new WaitingThreadAborter();
+
+ return new PoolEntryRequest() {
+
+ public void abortRequest() {
+ poolLock.lock();
+ try {
+ aborter.abort();
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+ public BasicPoolEntry getPoolEntry(
+ long timeout,
+ TimeUnit tunit)
+ throws InterruptedException, ConnectionPoolTimeoutException {
+ return getEntryBlocking(route, state, timeout, tunit, aborter);
+ }
+
+ };
+ }
+
+ /**
+ * Obtains a pool entry with a connection within the given timeout.
+ * If a {@link WaitingThread} is used to block, {@link WaitingThreadAborter#setWaitingThread(WaitingThread)}
+ * must be called before blocking, to allow the thread to be interrupted.
+ *
+ * @param route the route for which to get the connection
+ * @param timeout the timeout, 0 or negative for no timeout
+ * @param tunit the unit for the <code>timeout</code>,
+ * may be <code>null</code> only if there is no timeout
+ * @param aborter an object which can abort a {@link WaitingThread}.
+ *
+ * @return pool entry holding a connection for the route
+ *
+ * @throws ConnectionPoolTimeoutException
+ * if the timeout expired
+ * @throws InterruptedException
+ * if the calling thread was interrupted
+ */
+ protected BasicPoolEntry getEntryBlocking(
+ HttpRoute route, Object state,
+ long timeout, TimeUnit tunit,
+ WaitingThreadAborter aborter)
+ throws ConnectionPoolTimeoutException, InterruptedException {
+
+ Date deadline = null;
+ if (timeout > 0) {
+ deadline = new Date
+ (System.currentTimeMillis() + tunit.toMillis(timeout));
+ }
+
+ BasicPoolEntry entry = null;
+ poolLock.lock();
+ try {
+
+ RouteSpecificPool rospl = getRoutePool(route, true);
+ WaitingThread waitingThread = null;
+
+ while (entry == null) {
+
+ if (isShutDown) {
+ throw new IllegalStateException
+ ("Connection pool shut down.");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Total connections kept alive: " + freeConnections.size());
+ log.debug("Total issued connections: " + issuedConnections.size());
+ log.debug("Total allocated connection: " + numConnections + " out of " + maxTotalConnections);
+ }
+
+ // the cases to check for:
+ // - have a free connection for that route
+ // - allowed to create a free connection for that route
+ // - can delete and replace a free connection for another route
+ // - need to wait for one of the things above to come true
+
+ entry = getFreeEntry(rospl, state);
+ if (entry != null) {
+ break;
+ }
+
+ boolean hasCapacity = rospl.getCapacity() > 0;
+
+ if (log.isDebugEnabled()) {
+ log.debug("Available capacity: " + rospl.getCapacity()
+ + " out of " + rospl.getMaxEntries()
+ + " [" + route + "][" + state + "]");
+ }
+
+ if (hasCapacity && numConnections < maxTotalConnections) {
+
+ entry = createEntry(rospl, operator);
+
+ } else if (hasCapacity && !freeConnections.isEmpty()) {
+
+ deleteLeastUsedEntry();
+ entry = createEntry(rospl, operator);
+
+ } else {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Need to wait for connection" +
+ " [" + route + "][" + state + "]");
+ }
+
+ if (waitingThread == null) {
+ waitingThread =
+ newWaitingThread(poolLock.newCondition(), rospl);
+ aborter.setWaitingThread(waitingThread);
+ }
+
+ boolean success = false;
+ try {
+ rospl.queueThread(waitingThread);
+ waitingThreads.add(waitingThread);
+ success = waitingThread.await(deadline);
+
+ } finally {
+ // In case of 'success', we were woken up by the
+ // connection pool and should now have a connection
+ // waiting for us, or else we're shutting down.
+ // Just continue in the loop, both cases are checked.
+ rospl.removeThread(waitingThread);
+ waitingThreads.remove(waitingThread);
+ }
+
+ // check for spurious wakeup vs. timeout
+ if (!success && (deadline != null) &&
+ (deadline.getTime() <= System.currentTimeMillis())) {
+ throw new ConnectionPoolTimeoutException
+ ("Timeout waiting for connection");
+ }
+ }
+ } // while no entry
+
+ } finally {
+ poolLock.unlock();
+ }
+
+ return entry;
+
+ } // getEntry
+
+
+ // non-javadoc, see base class AbstractConnPool
+ @Override
+ public void freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit) {
+
+ HttpRoute route = entry.getPlannedRoute();
+ if (log.isDebugEnabled()) {
+ log.debug("Freeing connection" +
+ " [" + route + "][" + entry.getState() + "]");
+ }
+
+ poolLock.lock();
+ try {
+ if (isShutDown) {
+ // the pool is shut down, release the
+ // connection's resources and get out of here
+ closeConnection(entry.getConnection());
+ return;
+ }
+
+ // no longer issued, we keep a hard reference now
+ issuedConnections.remove(entry.getWeakRef());
+
+ RouteSpecificPool rospl = getRoutePool(route, true);
+
+ if (reusable) {
+ rospl.freeEntry(entry);
+ freeConnections.add(entry);
+ idleConnHandler.add(entry.getConnection(), validDuration, timeUnit);
+ } else {
+ rospl.dropEntry();
+ numConnections--;
+ }
+
+ notifyWaitingThread(rospl);
+
+ } finally {
+ poolLock.unlock();
+ }
+
+ } // freeEntry
+
+
+
+ /**
+ * If available, get a free pool entry for a route.
+ *
+ * @param rospl the route-specific pool from which to get an entry
+ *
+ * @return an available pool entry for the given route, or
+ * <code>null</code> if none is available
+ */
+ protected BasicPoolEntry getFreeEntry(RouteSpecificPool rospl, Object state) {
+
+ BasicPoolEntry entry = null;
+ poolLock.lock();
+ try {
+ boolean done = false;
+ while(!done) {
+
+ entry = rospl.allocEntry(state);
+
+ if (entry != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Getting free connection"
+ + " [" + rospl.getRoute() + "][" + state + "]");
+
+ }
+ freeConnections.remove(entry);
+ boolean valid = idleConnHandler.remove(entry.getConnection());
+ if(!valid) {
+ // If the free entry isn't valid anymore, get rid of it
+ // and loop to find another one that might be valid.
+ if(log.isDebugEnabled())
+ log.debug("Closing expired free connection"
+ + " [" + rospl.getRoute() + "][" + state + "]");
+ closeConnection(entry.getConnection());
+ // We use dropEntry instead of deleteEntry because the entry
+ // is no longer "free" (we just allocated it), and deleteEntry
+ // can only be used to delete free entries.
+ rospl.dropEntry();
+ numConnections--;
+ } else {
+ issuedConnections.add(entry.getWeakRef());
+ done = true;
+ }
+
+ } else {
+ done = true;
+ if (log.isDebugEnabled()) {
+ log.debug("No free connections"
+ + " [" + rospl.getRoute() + "][" + state + "]");
+ }
+ }
+ }
+ } finally {
+ poolLock.unlock();
+ }
+
+ return entry;
+ }
+
+
+ /**
+ * Creates a new pool entry.
+ * This method assumes that the new connection will be handed
+ * out immediately.
+ *
+ * @param rospl the route-specific pool for which to create the entry
+ * @param op the operator for creating a connection
+ *
+ * @return the new pool entry for a new connection
+ */
+ protected BasicPoolEntry createEntry(RouteSpecificPool rospl,
+ ClientConnectionOperator op) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Creating new connection [" + rospl.getRoute() + "]");
+ }
+
+ // the entry will create the connection when needed
+ BasicPoolEntry entry =
+ new BasicPoolEntry(op, rospl.getRoute(), refQueue);
+
+ poolLock.lock();
+ try {
+
+ rospl.createdEntry(entry);
+ numConnections++;
+
+ issuedConnections.add(entry.getWeakRef());
+
+ } finally {
+ poolLock.unlock();
+ }
+
+ return entry;
+ }
+
+
+ /**
+ * Deletes a given pool entry.
+ * This closes the pooled connection and removes all references,
+ * so that it can be GCed.
+ *
+ * <p><b>Note:</b> Does not remove the entry from the freeConnections list.
+ * It is assumed that the caller has already handled this step.</p>
+ * <!-- @@@ is that a good idea? or rather fix it? -->
+ *
+ * @param entry the pool entry for the connection to delete
+ */
+ protected void deleteEntry(BasicPoolEntry entry) {
+
+ HttpRoute route = entry.getPlannedRoute();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Deleting connection"
+ + " [" + route + "][" + entry.getState() + "]");
+ }
+
+ poolLock.lock();
+ try {
+
+ closeConnection(entry.getConnection());
+
+ RouteSpecificPool rospl = getRoutePool(route, true);
+ rospl.deleteEntry(entry);
+ numConnections--;
+ if (rospl.isUnused()) {
+ routeToPool.remove(route);
+ }
+
+ idleConnHandler.remove(entry.getConnection());// not idle, but dead
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ /**
+ * Delete an old, free pool entry to make room for a new one.
+ * Used to replace pool entries with ones for a different route.
+ */
+ protected void deleteLeastUsedEntry() {
+
+ try {
+ poolLock.lock();
+
+ //@@@ with get() instead of remove, we could
+ //@@@ leave the removing to deleteEntry()
+ BasicPoolEntry entry = freeConnections.remove();
+
+ if (entry != null) {
+ deleteEntry(entry);
+ } else if (log.isDebugEnabled()) {
+ log.debug("No free connection to delete.");
+ }
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ // non-javadoc, see base class AbstractConnPool
+ @Override
+ protected void handleLostEntry(HttpRoute route) {
+
+ poolLock.lock();
+ try {
+
+ RouteSpecificPool rospl = getRoutePool(route, true);
+ rospl.dropEntry();
+ if (rospl.isUnused()) {
+ routeToPool.remove(route);
+ }
+
+ numConnections--;
+ notifyWaitingThread(rospl);
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ /**
+ * Notifies a waiting thread that a connection is available.
+ * This will wake a thread waiting in the specific route pool,
+ * if there is one.
+ * Otherwise, a thread in the connection pool will be notified.
+ *
+ * @param rospl the pool in which to notify, or <code>null</code>
+ */
+ protected void notifyWaitingThread(RouteSpecificPool rospl) {
+
+ //@@@ while this strategy provides for best connection re-use,
+ //@@@ is it fair? only do this if the connection is open?
+ // Find the thread we are going to notify. We want to ensure that
+ // each waiting thread is only interrupted once, so we will remove
+ // it from all wait queues before interrupting.
+ WaitingThread waitingThread = null;
+
+ poolLock.lock();
+ try {
+
+ if ((rospl != null) && rospl.hasThread()) {
+ if (log.isDebugEnabled()) {
+ log.debug("Notifying thread waiting on pool" +
+ " [" + rospl.getRoute() + "]");
+ }
+ waitingThread = rospl.nextThread();
+ } else if (!waitingThreads.isEmpty()) {
+ if (log.isDebugEnabled()) {
+ log.debug("Notifying thread waiting on any pool");
+ }
+ waitingThread = waitingThreads.remove();
+ } else if (log.isDebugEnabled()) {
+ log.debug("Notifying no-one, there are no waiting threads");
+ }
+
+ if (waitingThread != null) {
+ waitingThread.wakeup();
+ }
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ //@@@ revise this cleanup stuff
+ //@@@ move method to base class when deleteEntry() is fixed
+ // non-javadoc, see base class AbstractConnPool
+ @Override
+ public void deleteClosedConnections() {
+
+ poolLock.lock();
+ try {
+
+ Iterator<BasicPoolEntry> iter = freeConnections.iterator();
+ while (iter.hasNext()) {
+ BasicPoolEntry entry = iter.next();
+ if (!entry.getConnection().isOpen()) {
+ iter.remove();
+ deleteEntry(entry);
+ }
+ }
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+ // non-javadoc, see base class AbstractConnPool
+ @Override
+ public void shutdown() {
+
+ poolLock.lock();
+ try {
+
+ super.shutdown();
+
+ // close all free connections
+ //@@@ move this to base class?
+ Iterator<BasicPoolEntry> ibpe = freeConnections.iterator();
+ while (ibpe.hasNext()) {
+ BasicPoolEntry entry = ibpe.next();
+ ibpe.remove();
+ closeConnection(entry.getConnection());
+ }
+
+ // wake up all waiting threads
+ Iterator<WaitingThread> iwth = waitingThreads.iterator();
+ while (iwth.hasNext()) {
+ WaitingThread waiter = iwth.next();
+ iwth.remove();
+ waiter.wakeup();
+ }
+
+ routeToPool.clear();
+
+ } finally {
+ poolLock.unlock();
+ }
+ }
+
+
+} // class ConnPoolByRoute
+
diff --git a/src/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java b/src/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java
new file mode 100644
index 0000000..faf5e3b
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java
@@ -0,0 +1,68 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java $
+ * $Revision: 652020 $
+ * $Date: 2008-04-27 14:23:31 -0700 (Sun, 27 Apr 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+
+/**
+ * Encapsulates a request for a {@link BasicPoolEntry}.
+ */
+public interface PoolEntryRequest {
+
+ /**
+ * Obtains a pool entry with a connection within the given timeout.
+ * If {@link #abortRequest()} is called before this completes
+ * an {@link InterruptedException} is thrown.
+ *
+ * @param timeout the timeout, 0 or negative for no timeout
+ * @param tunit the unit for the <code>timeout</code>,
+ * may be <code>null</code> only if there is no timeout
+ *
+ * @return pool entry holding a connection for the route
+ *
+ * @throws ConnectionPoolTimeoutException
+ * if the timeout expired
+ * @throws InterruptedException
+ * if the calling thread was interrupted or the request was aborted
+ */
+ BasicPoolEntry getPoolEntry(
+ long timeout,
+ TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException;
+
+ /**
+ * Aborts the active or next call to
+ * {@link #getPoolEntry(long, TimeUnit)}.
+ */
+ void abortRequest();
+
+}
diff --git a/src/org/apache/http/impl/conn/tsccm/RefQueueHandler.java b/src/org/apache/http/impl/conn/tsccm/RefQueueHandler.java
new file mode 100644
index 0000000..3af28cc
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/RefQueueHandler.java
@@ -0,0 +1,48 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/RefQueueHandler.java $
+ * $Revision: 603874 $
+ * $Date: 2007-12-13 02:42:41 -0800 (Thu, 13 Dec 2007) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.lang.ref.Reference;
+
+
+/**
+ * Callback handler for {@link RefQueueWorker RefQueueWorker}.
+ */
+public interface RefQueueHandler {
+
+ /**
+ * Invoked when a reference is found on the queue.
+ *
+ * @param ref the reference to handle
+ */
+ public void handleReference(Reference<?> ref)
+ ;
+}
diff --git a/src/org/apache/http/impl/conn/tsccm/RefQueueWorker.java b/src/org/apache/http/impl/conn/tsccm/RefQueueWorker.java
new file mode 100644
index 0000000..9ad5c77
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/RefQueueWorker.java
@@ -0,0 +1,139 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/RefQueueWorker.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+
+/**
+ * A worker thread for processing queued references.
+ * {@link Reference Reference}s can be
+ * {@link ReferenceQueue queued}
+ * automatically by the garbage collector.
+ * If that feature is used, a daemon thread should be executing
+ * this worker. It will pick up the queued references and pass them
+ * on to a handler for appropriate processing.
+ */
+public class RefQueueWorker implements Runnable {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The reference queue to monitor. */
+ protected final ReferenceQueue<?> refQueue;
+
+ /** The handler for the references found. */
+ protected final RefQueueHandler refHandler;
+
+
+ /**
+ * The thread executing this handler.
+ * This attribute is also used as a shutdown indicator.
+ */
+ protected volatile Thread workerThread;
+
+
+ /**
+ * Instantiates a new worker to listen for lost connections.
+ *
+ * @param queue the queue on which to wait for references
+ * @param handler the handler to pass the references to
+ */
+ public RefQueueWorker(ReferenceQueue<?> queue, RefQueueHandler handler) {
+ if (queue == null) {
+ throw new IllegalArgumentException("Queue must not be null.");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("Handler must not be null.");
+ }
+
+ refQueue = queue;
+ refHandler = handler;
+ }
+
+
+ /**
+ * The main loop of this worker.
+ * If initialization succeeds, this method will only return
+ * after {@link #shutdown shutdown()}. Only one thread can
+ * execute the main loop at any time.
+ */
+ public void run() {
+
+ if (this.workerThread == null) {
+ this.workerThread = Thread.currentThread();
+ }
+
+ while (this.workerThread == Thread.currentThread()) {
+ try {
+ // remove the next reference and process it
+ Reference<?> ref = refQueue.remove();
+ refHandler.handleReference(ref);
+ } catch (InterruptedException e) {
+ //@@@ is logging really necessary? this here is the
+ //@@@ only reason for having a log in this class
+ if (log.isDebugEnabled()) {
+ log.debug(this.toString() + " interrupted", e);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Shuts down this worker.
+ * It can be re-started afterwards by another call to {@link #run run()}.
+ */
+ public void shutdown() {
+ Thread wt = this.workerThread;
+ if (wt != null) {
+ this.workerThread = null; // indicate shutdown
+ wt.interrupt();
+ }
+ }
+
+
+ /**
+ * Obtains a description of this worker.
+ *
+ * @return a descriptive string for this worker
+ */
+ @Override
+ public String toString() {
+ return "RefQueueWorker::" + this.workerThread;
+ }
+
+} // class RefQueueWorker
+
diff --git a/src/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java b/src/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java
new file mode 100644
index 0000000..5c63933
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java
@@ -0,0 +1,301 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.io.IOException;
+import java.util.ListIterator;
+import java.util.Queue;
+import java.util.LinkedList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.util.LangUtils;
+
+
+/**
+ * A connection sub-pool for a specific route, used by {@link ConnPoolByRoute}.
+ * The methods in this class are unsynchronized. It is expected that the
+ * containing pool takes care of synchronization.
+ */
+public class RouteSpecificPool {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The route this pool is for. */
+ protected final HttpRoute route;
+
+ /** the maximum number of entries allowed for this pool */
+ protected final int maxEntries;
+
+ /**
+ * The list of free entries.
+ * This list is managed LIFO, to increase idle times and
+ * allow for closing connections that are not really needed.
+ */
+ protected final LinkedList<BasicPoolEntry> freeEntries;
+
+ /** The list of threads waiting for this pool. */
+ protected final Queue<WaitingThread> waitingThreads;
+
+ /** The number of created entries. */
+ protected int numEntries;
+
+
+ /**
+ * Creates a new route-specific pool.
+ *
+ * @param route the route for which to pool
+ * @param maxEntries the maximum number of entries allowed for this pool
+ */
+ public RouteSpecificPool(HttpRoute route, int maxEntries) {
+ this.route = route;
+ this.maxEntries = maxEntries;
+ this.freeEntries = new LinkedList<BasicPoolEntry>();
+ this.waitingThreads = new LinkedList<WaitingThread>();
+ this.numEntries = 0;
+ }
+
+
+ /**
+ * Obtains the route for which this pool is specific.
+ *
+ * @return the route
+ */
+ public final HttpRoute getRoute() {
+ return route;
+ }
+
+
+ /**
+ * Obtains the maximum number of entries allowed for this pool.
+ *
+ * @return the max entry number
+ */
+ public final int getMaxEntries() {
+ return maxEntries;
+ }
+
+
+ /**
+ * Indicates whether this pool is unused.
+ * A pool is unused if there is neither an entry nor a waiting thread.
+ * All entries count, not only the free but also the allocated ones.
+ *
+ * @return <code>true</code> if this pool is unused,
+ * <code>false</code> otherwise
+ */
+ public boolean isUnused() {
+ return (numEntries < 1) && waitingThreads.isEmpty();
+ }
+
+
+ /**
+ * Return remaining capacity of this pool
+ *
+ * @return capacity
+ */
+ public int getCapacity() {
+ return maxEntries - numEntries;
+ }
+
+
+ /**
+ * Obtains the number of entries.
+ * This includes not only the free entries, but also those that
+ * have been created and are currently issued to an application.
+ *
+ * @return the number of entries for the route of this pool
+ */
+ public final int getEntryCount() {
+ return numEntries;
+ }
+
+
+ /**
+ * Obtains a free entry from this pool, if one is available.
+ *
+ * @return an available pool entry, or <code>null</code> if there is none
+ */
+ public BasicPoolEntry allocEntry(final Object state) {
+ if (!freeEntries.isEmpty()) {
+ ListIterator<BasicPoolEntry> it = freeEntries.listIterator(freeEntries.size());
+ while (it.hasPrevious()) {
+ BasicPoolEntry entry = it.previous();
+ if (LangUtils.equals(state, entry.getState())) {
+ it.remove();
+ return entry;
+ }
+ }
+ }
+ if (!freeEntries.isEmpty()) {
+ BasicPoolEntry entry = freeEntries.remove();
+ entry.setState(null);
+ OperatedClientConnection conn = entry.getConnection();
+ try {
+ conn.close();
+ } catch (IOException ex) {
+ log.debug("I/O error closing connection", ex);
+ }
+ return entry;
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns an allocated entry to this pool.
+ *
+ * @param entry the entry obtained from {@link #allocEntry allocEntry}
+ * or presented to {@link #createdEntry createdEntry}
+ */
+ public void freeEntry(BasicPoolEntry entry) {
+
+ if (numEntries < 1) {
+ throw new IllegalStateException
+ ("No entry created for this pool. " + route);
+ }
+ if (numEntries <= freeEntries.size()) {
+ throw new IllegalStateException
+ ("No entry allocated from this pool. " + route);
+ }
+ freeEntries.add(entry);
+ }
+
+
+ /**
+ * Indicates creation of an entry for this pool.
+ * The entry will <i>not</i> be added to the list of free entries,
+ * it is only recognized as belonging to this pool now. It can then
+ * be passed to {@link #freeEntry freeEntry}.
+ *
+ * @param entry the entry that was created for this pool
+ */
+ public void createdEntry(BasicPoolEntry entry) {
+
+ if (!route.equals(entry.getPlannedRoute())) {
+ throw new IllegalArgumentException
+ ("Entry not planned for this pool." +
+ "\npool: " + route +
+ "\nplan: " + entry.getPlannedRoute());
+ }
+
+ numEntries++;
+ }
+
+
+ /**
+ * Deletes an entry from this pool.
+ * Only entries that are currently free in this pool can be deleted.
+ * Allocated entries can not be deleted.
+ *
+ * @param entry the entry to delete from this pool
+ *
+ * @return <code>true</code> if the entry was found and deleted, or
+ * <code>false</code> if the entry was not found
+ */
+ public boolean deleteEntry(BasicPoolEntry entry) {
+
+ final boolean found = freeEntries.remove(entry);
+ if (found)
+ numEntries--;
+ return found;
+ }
+
+
+ /**
+ * Forgets about an entry from this pool.
+ * This method is used to indicate that an entry
+ * {@link #allocEntry allocated}
+ * from this pool has been lost and will not be returned.
+ */
+ public void dropEntry() {
+ if (numEntries < 1) {
+ throw new IllegalStateException
+ ("There is no entry that could be dropped.");
+ }
+ numEntries--;
+ }
+
+
+ /**
+ * Adds a waiting thread.
+ * This pool makes no attempt to match waiting threads with pool entries.
+ * It is the caller's responsibility to check that there is no entry
+ * before adding a waiting thread.
+ *
+ * @param wt the waiting thread
+ */
+ public void queueThread(WaitingThread wt) {
+ if (wt == null) {
+ throw new IllegalArgumentException
+ ("Waiting thread must not be null.");
+ }
+ this.waitingThreads.add(wt);
+ }
+
+
+ /**
+ * Checks whether there is a waiting thread in this pool.
+ *
+ * @return <code>true</code> if there is a waiting thread,
+ * <code>false</code> otherwise
+ */
+ public boolean hasThread() {
+ return !this.waitingThreads.isEmpty();
+ }
+
+
+ /**
+ * Returns the next thread in the queue.
+ *
+ * @return a waiting thread, or <code>null</code> if there is none
+ */
+ public WaitingThread nextThread() {
+ return this.waitingThreads.peek();
+ }
+
+
+ /**
+ * Removes a waiting thread, if it is queued.
+ *
+ * @param wt the waiting thread
+ */
+ public void removeThread(WaitingThread wt) {
+ if (wt == null)
+ return;
+
+ this.waitingThreads.remove(wt);
+ }
+
+
+} // class RouteSpecificPool
diff --git a/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java b/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
new file mode 100644
index 0000000..0781e05
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
@@ -0,0 +1,282 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java $
+ * $Revision: 673450 $
+ * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.params.HttpParams;
+import org.apache.http.impl.conn.DefaultClientConnectionOperator;
+
+
+
+/**
+ * Manages a pool of {@link OperatedClientConnection client connections}.
+ * <p>
+ * This class is derived from <code>MultiThreadedHttpConnectionManager</code>
+ * in HttpClient 3. See there for original authors.
+ * </p>
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision: 673450 $ $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
+ *
+ * @since 4.0
+ */
+public class ThreadSafeClientConnManager implements ClientConnectionManager {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** The schemes supported by this connection manager. */
+ protected SchemeRegistry schemeRegistry;
+
+ /** The pool of connections being managed. */
+ protected final AbstractConnPool connectionPool;
+
+ /** The operator for opening and updating connections. */
+ protected ClientConnectionOperator connOperator;
+
+
+
+ /**
+ * Creates a new thread safe connection manager.
+ *
+ * @param params the parameters for this manager
+ * @param schreg the scheme registry, or
+ * <code>null</code> for the default registry
+ */
+ public ThreadSafeClientConnManager(HttpParams params,
+ SchemeRegistry schreg) {
+
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.schemeRegistry = schreg;
+ this.connOperator = createConnectionOperator(schreg);
+ this.connectionPool = createConnectionPool(params);
+
+ } // <constructor>
+
+
+ @Override
+ protected void finalize() throws Throwable {
+ shutdown();
+ super.finalize();
+ }
+
+
+ /**
+ * Hook for creating the connection pool.
+ *
+ * @return the connection pool to use
+ */
+ protected AbstractConnPool createConnectionPool(final HttpParams params) {
+
+ AbstractConnPool acp = new ConnPoolByRoute(connOperator, params);
+ boolean conngc = true; //@@@ check parameters to decide
+ if (conngc) {
+ acp.enableConnectionGC();
+ }
+ return acp;
+ }
+
+
+ /**
+ * Hook for creating the connection operator.
+ * It is called by the constructor.
+ * Derived classes can override this method to change the
+ * instantiation of the operator.
+ * The default implementation here instantiates
+ * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
+ *
+ * @param schreg the scheme registry to use, or <code>null</code>
+ *
+ * @return the connection operator to use
+ */
+ protected ClientConnectionOperator
+ createConnectionOperator(SchemeRegistry schreg) {
+
+ return new DefaultClientConnectionOperator(schreg);
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public SchemeRegistry getSchemeRegistry() {
+ return this.schemeRegistry;
+ }
+
+
+ public ClientConnectionRequest requestConnection(
+ final HttpRoute route,
+ final Object state) {
+
+ final PoolEntryRequest poolRequest = connectionPool.requestPoolEntry(
+ route, state);
+
+ return new ClientConnectionRequest() {
+
+ public void abortRequest() {
+ poolRequest.abortRequest();
+ }
+
+ public ManagedClientConnection getConnection(
+ long timeout, TimeUnit tunit) throws InterruptedException,
+ ConnectionPoolTimeoutException {
+ if (route == null) {
+ throw new IllegalArgumentException("Route may not be null.");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("ThreadSafeClientConnManager.getConnection: "
+ + route + ", timeout = " + timeout);
+ }
+
+ BasicPoolEntry entry = poolRequest.getPoolEntry(timeout, tunit);
+ return new BasicPooledConnAdapter(ThreadSafeClientConnManager.this, entry);
+ }
+
+ };
+
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
+
+ if (!(conn instanceof BasicPooledConnAdapter)) {
+ throw new IllegalArgumentException
+ ("Connection class mismatch, " +
+ "connection not obtained from this manager.");
+ }
+ BasicPooledConnAdapter hca = (BasicPooledConnAdapter) conn;
+ if ((hca.getPoolEntry() != null) && (hca.getManager() != this)) {
+ throw new IllegalArgumentException
+ ("Connection not obtained from this manager.");
+ }
+
+ try {
+ // make sure that the response has been read completely
+ if (hca.isOpen() && !hca.isMarkedReusable()) {
+ if (log.isDebugEnabled()) {
+ log.debug
+ ("Released connection open but not marked reusable.");
+ }
+ // In MTHCM, there would be a call to
+ // SimpleHttpConnectionManager.finishLastResponse(conn);
+ // Consuming the response is handled outside in 4.0.
+
+ // make sure this connection will not be re-used
+ // Shut down rather than close, we might have gotten here
+ // because of a shutdown trigger.
+ // Shutdown of the adapter also clears the tracked route.
+ hca.shutdown();
+ }
+ } catch (IOException iox) {
+ //@@@ log as warning? let pass?
+ if (log.isDebugEnabled())
+ log.debug("Exception shutting down released connection.",
+ iox);
+ } finally {
+ BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
+ boolean reusable = hca.isMarkedReusable();
+ hca.detach();
+ if (entry != null) {
+ connectionPool.freeEntry(entry, reusable, validDuration, timeUnit);
+ }
+ }
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public void shutdown() {
+ connectionPool.shutdown();
+ }
+
+
+ /**
+ * Gets the total number of pooled connections for the given route.
+ * This is the total number of connections that have been created and
+ * are still in use by this connection manager for the route.
+ * This value will not exceed the maximum number of connections per host.
+ *
+ * @param route the route in question
+ *
+ * @return the total number of pooled connections for that route
+ */
+ public int getConnectionsInPool(HttpRoute route) {
+ return ((ConnPoolByRoute)connectionPool).getConnectionsInPool(
+ route);
+ }
+
+
+ /**
+ * Gets the total number of pooled connections. This is the total number of
+ * connections that have been created and are still in use by this connection
+ * manager. This value will not exceed the maximum number of connections
+ * in total.
+ *
+ * @return the total number of pooled connections
+ */
+ public int getConnectionsInPool() {
+ synchronized (connectionPool) {
+ return connectionPool.numConnections; //@@@
+ }
+ }
+
+
+ // non-javadoc, see interface ClientConnectionManager
+ public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
+ // combine these two in a single call?
+ connectionPool.closeIdleConnections(idleTimeout, tunit);
+ connectionPool.deleteClosedConnections();
+ }
+
+ public void closeExpiredConnections() {
+ connectionPool.closeExpiredConnections();
+ connectionPool.deleteClosedConnections();
+ }
+
+
+} // class ThreadSafeClientConnManager
+
diff --git a/src/org/apache/http/impl/conn/tsccm/WaitingThread.java b/src/org/apache/http/impl/conn/tsccm/WaitingThread.java
new file mode 100644
index 0000000..a50e11f
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/WaitingThread.java
@@ -0,0 +1,197 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/WaitingThread.java $
+ * $Revision: 649217 $
+ * $Date: 2008-04-17 11:32:32 -0700 (Thu, 17 Apr 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+
+import java.util.Date;
+import java.util.concurrent.locks.Condition;
+
+
+/**
+ * Represents a thread waiting for a connection.
+ * This class implements throwaway objects. It is instantiated whenever
+ * a thread needs to wait. Instances are not re-used, except if the
+ * waiting thread experiences a spurious wakeup and continues to wait.
+ * <br/>
+ * All methods assume external synchronization on the condition
+ * passed to the constructor.
+ * Instances of this class do <i>not</i> synchronize access!
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ */
+public class WaitingThread {
+
+ /** The condition on which the thread is waiting. */
+ private final Condition cond;
+
+ /** The route specific pool on which the thread is waiting. */
+ //@@@ replace with generic pool interface
+ private final RouteSpecificPool pool;
+
+ /** The thread that is waiting for an entry. */
+ private Thread waiter;
+
+ /** True if this was interrupted. */
+ private boolean aborted;
+
+
+ /**
+ * Creates a new entry for a waiting thread.
+ *
+ * @param cond the condition for which to wait
+ * @param pool the pool on which the thread will be waiting,
+ * or <code>null</code>
+ */
+ public WaitingThread(Condition cond, RouteSpecificPool pool) {
+
+ if (cond == null) {
+ throw new IllegalArgumentException("Condition must not be null.");
+ }
+
+ this.cond = cond;
+ this.pool = pool;
+ }
+
+
+ /**
+ * Obtains the condition.
+ *
+ * @return the condition on which to wait, never <code>null</code>
+ */
+ public final Condition getCondition() {
+ // not synchronized
+ return this.cond;
+ }
+
+
+ /**
+ * Obtains the pool, if there is one.
+ *
+ * @return the pool on which a thread is or was waiting,
+ * or <code>null</code>
+ */
+ public final RouteSpecificPool getPool() {
+ // not synchronized
+ return this.pool;
+ }
+
+
+ /**
+ * Obtains the thread, if there is one.
+ *
+ * @return the thread which is waiting, or <code>null</code>
+ */
+ public final Thread getThread() {
+ // not synchronized
+ return this.waiter;
+ }
+
+
+ /**
+ * Blocks the calling thread.
+ * This method returns when the thread is notified or interrupted,
+ * if a timeout occurrs, or if there is a spurious wakeup.
+ * <br/>
+ * This method assumes external synchronization.
+ *
+ * @param deadline when to time out, or <code>null</code> for no timeout
+ *
+ * @return <code>true</code> if the condition was satisfied,
+ * <code>false</code> in case of a timeout.
+ * Typically, a call to {@link #wakeup} is used to indicate
+ * that the condition was satisfied. Since the condition is
+ * accessible outside, this cannot be guaranteed though.
+ *
+ * @throws InterruptedException if the waiting thread was interrupted
+ *
+ * @see #wakeup
+ */
+ public boolean await(Date deadline)
+ throws InterruptedException {
+
+ // This is only a sanity check. We cannot synchronize here,
+ // the lock would not be released on calling cond.await() below.
+ if (this.waiter != null) {
+ throw new IllegalStateException
+ ("A thread is already waiting on this object." +
+ "\ncaller: " + Thread.currentThread() +
+ "\nwaiter: " + this.waiter);
+ }
+
+ if (aborted)
+ throw new InterruptedException("Operation interrupted");
+
+ this.waiter = Thread.currentThread();
+
+ boolean success = false;
+ try {
+ if (deadline != null) {
+ success = this.cond.awaitUntil(deadline);
+ } else {
+ this.cond.await();
+ success = true;
+ }
+ if (aborted)
+ throw new InterruptedException("Operation interrupted");
+ } finally {
+ this.waiter = null;
+ }
+ return success;
+
+ } // await
+
+
+ /**
+ * Wakes up the waiting thread.
+ * <br/>
+ * This method assumes external synchronization.
+ */
+ public void wakeup() {
+
+ // If external synchronization and pooling works properly,
+ // this cannot happen. Just a sanity check.
+ if (this.waiter == null) {
+ throw new IllegalStateException
+ ("Nobody waiting on this object.");
+ }
+
+ // One condition might be shared by several WaitingThread instances.
+ // It probably isn't, but just in case: wake all, not just one.
+ this.cond.signalAll();
+ }
+
+ public void interrupt() {
+ aborted = true;
+ this.cond.signalAll();
+ }
+
+
+} // class WaitingThread
diff --git a/src/org/apache/http/impl/conn/tsccm/WaitingThreadAborter.java b/src/org/apache/http/impl/conn/tsccm/WaitingThreadAborter.java
new file mode 100644
index 0000000..1844457
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/WaitingThreadAborter.java
@@ -0,0 +1,62 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/WaitingThreadAborter.java $
+ * $Revision: 649220 $
+ * $Date: 2008-04-17 11:40:24 -0700 (Thu, 17 Apr 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.conn.tsccm;
+
+/** A simple class that can interrupt a {@link WaitingThread}. */
+public class WaitingThreadAborter {
+
+ private WaitingThread waitingThread;
+ private boolean aborted;
+
+ /**
+ * If a waiting thread has been set, interrupts it.
+ */
+ public void abort() {
+ aborted = true;
+
+ if (waitingThread != null)
+ waitingThread.interrupt();
+
+ }
+
+ /**
+ * Sets the waiting thread. If this has already been aborted,
+ * the waiting thread is immediately interrupted.
+ *
+ * @param waitingThread The thread to interrupt when aborting.
+ */
+ public void setWaitingThread(WaitingThread waitingThread) {
+ this.waitingThread = waitingThread;
+ if (aborted)
+ waitingThread.interrupt();
+ }
+
+}
diff --git a/src/org/apache/http/impl/conn/tsccm/doc-files/tsccm-structure.png b/src/org/apache/http/impl/conn/tsccm/doc-files/tsccm-structure.png
new file mode 100644
index 0000000..2e2820d
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/doc-files/tsccm-structure.png
Binary files differ
diff --git a/src/org/apache/http/impl/conn/tsccm/package.html b/src/org/apache/http/impl/conn/tsccm/package.html
new file mode 100644
index 0000000..5aca5d4
--- /dev/null
+++ b/src/org/apache/http/impl/conn/tsccm/package.html
@@ -0,0 +1,205 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/package.html $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+
+The implementation of a thread-safe client connection manager.
+
+<center>
+<img src="doc-files/tsccm-structure.png" alt="Relation Diagram"/>
+</center>
+
+<p>
+The implementation is structured into three areas, as illustrated
+by the diagram above.
+Facing the application is the <i>Manager</i> (green), which internally
+maintains a <i>Pool</i> (yellow) of connections and waiting threads.
+Both Manager and Pool rely on <i>Operations</i> (cyan) to provide the
+actual connections.
+</p>
+<p>
+In order to allow connection garbage collection, it is
+imperative that hard object references between the areas are
+restricted to the relations indicated by arrows in the diagram:
+</p>
+<ul>
+<li>Applications reference only the Manager objects.</li>
+<li>Manager objects reference Pool objects, but not vice versa.</li>
+<li>Operations objects do not reference either Manager or Pool objects.</li>
+</ul>
+
+<p>
+The following table shows a selection of classes and interfaces,
+and their assignment to the three areas.
+</p>
+<center>
+<table border="1">
+<colgroup>
+ <col width="50%"/>
+ <col width="50%"/>
+</colgroup>
+
+<tr>
+<td style="text-align: center; background-color: #00ff00;">
+{@link org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager}
+</td>
+<td style="text-align: center; background-color: #ffff00;">
+{@link org.apache.http.impl.conn.tsccm.AbstractConnPool}
+</td>
+</tr>
+
+<tr>
+<td style="text-align: center; background-color: #00ff00;">
+{@link org.apache.http.impl.conn.tsccm.BasicPooledConnAdapter}
+</td>
+<td style="text-align: center; background-color: #ffff00;">
+{@link org.apache.http.impl.conn.tsccm.ConnPoolByRoute}
+</td>
+</tr>
+
+<!-- appears on both sides! -->
+
+<tr>
+<td style="text-align: right; background-color: #00ff00;">
+{@link org.apache.http.impl.conn.tsccm.BasicPoolEntry}
+</td>
+<td style="text-align: left; background-color: #ffff00;">
+{@link org.apache.http.impl.conn.tsccm.BasicPoolEntry}
+</td>
+</tr>
+
+<!-- ====================== -->
+
+<tr style="border-width: 5px;">
+</tr>
+
+<tr>
+<td colspan="2" style="text-align: center; background-color: #00ffff;">
+{@link org.apache.http.conn.ClientConnectionOperator}
+</td>
+</tr>
+
+<tr>
+<td colspan="2" style="text-align: center; background-color: #00ffff;">
+{@link org.apache.http.conn.OperatedClientConnection}
+</td>
+</tr>
+
+</table>
+</center>
+
+<p>
+The Manager area has implementations for the connection management
+interfaces {@link org.apache.http.conn.ClientConnectionManager}
+and {@link org.apache.http.conn.ManagedClientConnection}.
+The latter is an adapter from managed to operated connections, based on a
+{@link org.apache.http.impl.conn.tsccm.BasicPoolEntry}.
+<br/>
+The Pool area shows an abstract pool class
+{@link org.apache.http.impl.conn.tsccm.AbstractConnPool}
+and a concrete implementation
+{@link org.apache.http.impl.conn.tsccm.ConnPoolByRoute}
+which uses the same basic algorithm as the
+<code>MultiThreadedHttpConnectionManager</code>
+in HttpClient 3.x.
+A pool contains instances of
+{@link org.apache.http.impl.conn.tsccm.BasicPoolEntry}.
+Most other classes in this package also belong to the Pool area.
+<br/>
+In the Operations area, you will find only the interfaces for
+operated connections as defined in the org.apache.http.conn package.
+The connection manager will work with all correct implementations
+of these interfaces. This package therefore does not define anything
+specific to the Operations area.
+</p>
+
+<p>
+As you have surely noticed, the
+{@link org.apache.http.impl.conn.tsccm.BasicPoolEntry}
+appears in both the Manager and Pool areas.
+This is where things get tricky for connection garbage collection.
+<br/>
+A connection pool may start a background thread to implement cleanup.
+In that case, the connection pool will not be garbage collected until
+it is shut down, since the background thread keeps a hard reference
+to the pool. The pool itself keeps hard references to the pooled entries,
+which in turn reference idle connections. Neither of these is subject
+to garbage collection.
+Only the shutdown of the pool will stop the background thread,
+thereby enabling garbage collection of the pool objects.
+<br/>
+A pool entry that is passed to an application by means of a connection
+adapter will move from the Pool area to the Manager area. When the
+connection is released by the application, the manager returns the
+entry back to the pool. With that step, the pool entry moves from
+the Manager area back to the Pool area.
+While the entry is in the Manager area, the pool MUST NOT keep a
+hard reference to it.
+</p>
+
+<p>
+The purpose of connection garbage collection is to detect when an
+application fails to return a connection. In order to achieve this,
+the only hard reference to the pool entry in the Manager area is
+in the connection wrapper. The manager will not keep a hard reference
+to the connection wrapper either, since that wrapper is effectively
+moving to the Application area.
+If the application drops it's reference to the connection wrapper,
+that wrapper will be garbage collected, and with it the pool entry.
+<br/>
+In order to detect garbage collection of pool entries handed out
+to the application, the pool keeps a <i>weak reference</i> to the
+entry. Instances of
+{@link org.apache.http.impl.conn.tsccm.BasicPoolEntryRef}
+combine the weak reference with information about the route for
+which the pool entry was allocated. If one of these entry references
+becomes stale, the pool can accommodate for the lost connection.
+This is triggered either by a background thread waiting for the
+references to be queued by the garbage collector, or by the
+application calling a {@link
+ org.apache.http.conn.ClientConnectionManager#closeIdleConnections cleanup}
+method of the connection manager.
+<br/>
+Basically the same trick is used for detecting garbage collection
+of the connection manager itself. The pool keeps a weak reference
+to the connection manager that created it. However, this will work
+only if there is a background thread to detect when that reference
+is queued by the garbage collector. Otherwise, a finalizer of the
+connection manager will shut down the pool and release it's resources.
+</p>
+
+
+</body>
+</html>
diff --git a/src/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java b/src/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java
new file mode 100644
index 0000000..1aa4d2c
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java
@@ -0,0 +1,50 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java $
+ * $Revision: 503525 $
+ * $Date: 2007-02-04 17:15:08 -0800 (Sun, 04 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+
+public abstract class AbstractCookieAttributeHandler implements CookieAttributeHandler {
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ // Do nothing
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ // Always match
+ return true;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/AbstractCookieSpec.java b/src/org/apache/http/impl/cookie/AbstractCookieSpec.java
new file mode 100644
index 0000000..3e47a4d
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/AbstractCookieSpec.java
@@ -0,0 +1,110 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java $
+ * $Revision: 617207 $
+ * $Date: 2008-01-31 12:14:12 -0800 (Thu, 31 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieSpec;
+
+/**
+ * Abstract cookie specification which can delegate the job of parsing,
+ * validation or matching cookie attributes to a number of arbitrary
+ * {@link CookieAttributeHandler}s.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public abstract class AbstractCookieSpec implements CookieSpec {
+
+ /**
+ * Stores attribute name -> attribute handler mappings
+ */
+ private final Map<String, CookieAttributeHandler> attribHandlerMap;
+
+ /**
+ * Default constructor
+ * */
+ public AbstractCookieSpec() {
+ super();
+ this.attribHandlerMap = new HashMap<String, CookieAttributeHandler>(10);
+ }
+
+ public void registerAttribHandler(
+ final String name, final CookieAttributeHandler handler) {
+ if (name == null) {
+ throw new IllegalArgumentException("Attribute name may not be null");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("Attribute handler may not be null");
+ }
+ this.attribHandlerMap.put(name, handler);
+ }
+
+ /**
+ * Finds an attribute handler {@link CookieAttributeHandler} for the
+ * given attribute. Returns <tt>null</tt> if no attribute handler is
+ * found for the specified attribute.
+ *
+ * @param name attribute name. e.g. Domain, Path, etc.
+ * @return an attribute handler or <tt>null</tt>
+ */
+ protected CookieAttributeHandler findAttribHandler(final String name) {
+ return this.attribHandlerMap.get(name);
+ }
+
+ /**
+ * Gets attribute handler {@link CookieAttributeHandler} for the
+ * given attribute.
+ *
+ * @param name attribute name. e.g. Domain, Path, etc.
+ * @throws IllegalStateException if handler not found for the
+ * specified attribute.
+ */
+ protected CookieAttributeHandler getAttribHandler(final String name) {
+ CookieAttributeHandler handler = findAttribHandler(name);
+ if (handler == null) {
+ throw new IllegalStateException("Handler not registered for " +
+ name + " attribute.");
+ } else {
+ return handler;
+ }
+ }
+
+ protected Collection<CookieAttributeHandler> getAttribHandlers() {
+ return this.attribHandlerMap.values();
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BasicClientCookie.java b/src/org/apache/http/impl/cookie/BasicClientCookie.java
new file mode 100644
index 0000000..6ec6c2b
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicClientCookie.java
@@ -0,0 +1,376 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java $
+ * $Revision: 659191 $
+ * $Date: 2008-05-22 11:26:53 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.SetCookie;
+
+/**
+ * HTTP "magic-cookie" represents a piece of state information
+ * that the HTTP agent and the target server can exchange to maintain
+ * a session.
+ *
+ * @author B.C. Holmes
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
+ * @author Rod Waldhoff
+ * @author dIon Gillard
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
+ * @author Marc A. Saegesser
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @version $Revision: 659191 $
+ */
+public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable {
+
+ /**
+ * Default Constructor taking a name and a value. The value may be null.
+ *
+ * @param name The name.
+ * @param value The value.
+ */
+ public BasicClientCookie(final String name, final String value) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.attribs = new HashMap<String, String>();
+ this.value = value;
+ }
+
+ /**
+ * Returns the name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+ /**
+ * Sets the value
+ *
+ * @param value
+ */
+ public void setValue(final String value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns the comment describing the purpose of this cookie, or
+ * <tt>null</tt> if no such comment has been defined.
+ *
+ * @return comment
+ *
+ * @see #setComment(String)
+ */
+ public String getComment() {
+ return cookieComment;
+ }
+
+ /**
+ * If a user agent (web browser) presents this cookie to a user, the
+ * cookie's purpose will be described using this comment.
+ *
+ * @param comment
+ *
+ * @see #getComment()
+ */
+ public void setComment(String comment) {
+ cookieComment = comment;
+ }
+
+
+ /**
+ * Returns null. Cookies prior to RFC2965 do not set this attribute
+ */
+ public String getCommentURL() {
+ return null;
+ }
+
+
+ /**
+ * Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
+ * if none exists.
+ * <p><strong>Note:</strong> the object returned by this method is
+ * considered immutable. Changing it (e.g. using setTime()) could result
+ * in undefined behaviour. Do so at your peril. </p>
+ * @return Expiration {@link Date}, or <tt>null</tt>.
+ *
+ * @see #setExpiryDate(java.util.Date)
+ *
+ */
+ public Date getExpiryDate() {
+ return cookieExpiryDate;
+ }
+
+ /**
+ * Sets expiration date.
+ * <p><strong>Note:</strong> the object returned by this method is considered
+ * immutable. Changing it (e.g. using setTime()) could result in undefined
+ * behaviour. Do so at your peril.</p>
+ *
+ * @param expiryDate the {@link Date} after which this cookie is no longer valid.
+ *
+ * @see #getExpiryDate
+ *
+ */
+ public void setExpiryDate (Date expiryDate) {
+ cookieExpiryDate = expiryDate;
+ }
+
+
+ /**
+ * Returns <tt>false</tt> if the cookie should be discarded at the end
+ * of the "session"; <tt>true</tt> otherwise.
+ *
+ * @return <tt>false</tt> if the cookie should be discarded at the end
+ * of the "session"; <tt>true</tt> otherwise
+ */
+ public boolean isPersistent() {
+ return (null != cookieExpiryDate);
+ }
+
+
+ /**
+ * Returns domain attribute of the cookie.
+ *
+ * @return the value of the domain attribute
+ *
+ * @see #setDomain(java.lang.String)
+ */
+ public String getDomain() {
+ return cookieDomain;
+ }
+
+ /**
+ * Sets the domain attribute.
+ *
+ * @param domain The value of the domain attribute
+ *
+ * @see #getDomain
+ */
+ public void setDomain(String domain) {
+ if (domain != null) {
+ cookieDomain = domain.toLowerCase(Locale.ENGLISH);
+ } else {
+ cookieDomain = null;
+ }
+ }
+
+
+ /**
+ * Returns the path attribute of the cookie
+ *
+ * @return The value of the path attribute.
+ *
+ * @see #setPath(java.lang.String)
+ */
+ public String getPath() {
+ return cookiePath;
+ }
+
+ /**
+ * Sets the path attribute.
+ *
+ * @param path The value of the path attribute
+ *
+ * @see #getPath
+ *
+ */
+ public void setPath(String path) {
+ cookiePath = path;
+ }
+
+ /**
+ * @return <code>true</code> if this cookie should only be sent over secure connections.
+ * @see #setSecure(boolean)
+ */
+ public boolean isSecure() {
+ return isSecure;
+ }
+
+ /**
+ * Sets the secure attribute of the cookie.
+ * <p>
+ * When <tt>true</tt> the cookie should only be sent
+ * using a secure protocol (https). This should only be set when
+ * the cookie's originating server used a secure protocol to set the
+ * cookie's value.
+ *
+ * @param secure The value of the secure attribute
+ *
+ * @see #isSecure()
+ */
+ public void setSecure (boolean secure) {
+ isSecure = secure;
+ }
+
+
+ /**
+ * Returns null. Cookies prior to RFC2965 do not set this attribute
+ */
+ public int[] getPorts() {
+ return null;
+ }
+
+
+ /**
+ * Returns the version of the cookie specification to which this
+ * cookie conforms.
+ *
+ * @return the version of the cookie.
+ *
+ * @see #setVersion(int)
+ *
+ */
+ public int getVersion() {
+ return cookieVersion;
+ }
+
+ /**
+ * Sets the version of the cookie specification to which this
+ * cookie conforms.
+ *
+ * @param version the version of the cookie.
+ *
+ * @see #getVersion
+ */
+ public void setVersion(int version) {
+ cookieVersion = version;
+ }
+
+ /**
+ * Returns true if this cookie has expired.
+ * @param date Current time
+ *
+ * @return <tt>true</tt> if the cookie has expired.
+ */
+ public boolean isExpired(final Date date) {
+ if (date == null) {
+ throw new IllegalArgumentException("Date may not be null");
+ }
+ return (cookieExpiryDate != null
+ && cookieExpiryDate.getTime() <= date.getTime());
+ }
+
+ public void setAttribute(final String name, final String value) {
+ this.attribs.put(name, value);
+ }
+
+ public String getAttribute(final String name) {
+ return this.attribs.get(name);
+ }
+
+ public boolean containsAttribute(final String name) {
+ return this.attribs.get(name) != null;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ BasicClientCookie clone = (BasicClientCookie) super.clone();
+ clone.attribs = new HashMap<String, String>(this.attribs);
+ return clone;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("[version: ");
+ buffer.append(Integer.toString(this.cookieVersion));
+ buffer.append("]");
+ buffer.append("[name: ");
+ buffer.append(this.name);
+ buffer.append("]");
+ buffer.append("[value: ");
+ buffer.append(this.value);
+ buffer.append("]");
+ buffer.append("[domain: ");
+ buffer.append(this.cookieDomain);
+ buffer.append("]");
+ buffer.append("[path: ");
+ buffer.append(this.cookiePath);
+ buffer.append("]");
+ buffer.append("[expiry: ");
+ buffer.append(this.cookieExpiryDate);
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+ // ----------------------------------------------------- Instance Variables
+
+ /** Cookie name */
+ private final String name;
+
+ /** Cookie attributes as specified by the origin server */
+ private Map<String, String> attribs;
+
+ /** Cookie value */
+ private String value;
+
+ /** Comment attribute. */
+ private String cookieComment;
+
+ /** Domain attribute. */
+ private String cookieDomain;
+
+ /** Expiration {@link Date}. */
+ private Date cookieExpiryDate;
+
+ /** Path attribute. */
+ private String cookiePath;
+
+ /** My secure flag. */
+ private boolean isSecure;
+
+ /** The version of the cookie specification I was created from. */
+ private int cookieVersion;
+
+}
+
diff --git a/src/org/apache/http/impl/cookie/BasicClientCookie2.java b/src/org/apache/http/impl/cookie/BasicClientCookie2.java
new file mode 100644
index 0000000..86ec60d
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicClientCookie2.java
@@ -0,0 +1,101 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java $
+ * $Revision: 659191 $
+ * $Date: 2008-05-22 11:26:53 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.Date;
+
+import org.apache.http.cookie.SetCookie2;
+
+/**
+ * HTTP "magic-cookie" represents a piece of state information
+ * that the HTTP agent and the target server can exchange to maintain
+ * a session as specified by RFC2965.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class BasicClientCookie2 extends BasicClientCookie implements SetCookie2 {
+
+ private String commentURL;
+ private int[] ports;
+ private boolean discard;
+
+ /**
+ * Default Constructor taking a name and a value. The value may be null.
+ *
+ * @param name The name.
+ * @param value The value.
+ */
+ public BasicClientCookie2(final String name, final String value) {
+ super(name, value);
+ }
+
+ @Override
+ public int[] getPorts() {
+ return this.ports;
+ }
+
+ public void setPorts(final int[] ports) {
+ this.ports = ports;
+ }
+
+ @Override
+ public String getCommentURL() {
+ return this.commentURL;
+ }
+
+ public void setCommentURL(final String commentURL) {
+ this.commentURL = commentURL;
+ }
+
+ public void setDiscard(boolean discard) {
+ this.discard = discard;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return !this.discard && super.isPersistent();
+ }
+
+ @Override
+ public boolean isExpired(final Date date) {
+ return this.discard || super.isExpired(date);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ BasicClientCookie2 clone = (BasicClientCookie2) super.clone();
+ clone.ports = this.ports.clone();
+ return clone;
+ }
+
+}
+
diff --git a/src/org/apache/http/impl/cookie/BasicCommentHandler.java b/src/org/apache/http/impl/cookie/BasicCommentHandler.java
new file mode 100644
index 0000000..ce8baea
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicCommentHandler.java
@@ -0,0 +1,50 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java $
+ * $Revision: 558519 $
+ * $Date: 2007-07-22 11:19:49 -0700 (Sun, 22 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class BasicCommentHandler extends AbstractCookieAttributeHandler {
+
+ public BasicCommentHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ cookie.setComment(value);
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BasicDomainHandler.java b/src/org/apache/http/impl/cookie/BasicDomainHandler.java
new file mode 100644
index 0000000..267faf8
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicDomainHandler.java
@@ -0,0 +1,122 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class BasicDomainHandler implements CookieAttributeHandler {
+
+ public BasicDomainHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null) {
+ throw new MalformedCookieException("Missing value for domain attribute");
+ }
+ if (value.trim().length() == 0) {
+ throw new MalformedCookieException("Blank value for domain attribute");
+ }
+ cookie.setDomain(value);
+ }
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ // Validate the cookies domain attribute. NOTE: Domains without
+ // any dots are allowed to support hosts on private LANs that don't
+ // have DNS names. Since they have no dots, to domain-match the
+ // request-host and domain must be identical for the cookie to sent
+ // back to the origin-server.
+ String host = origin.getHost();
+ String domain = cookie.getDomain();
+ if (domain == null) {
+ throw new MalformedCookieException("Cookie domain may not be null");
+ }
+ if (host.contains(".")) {
+ // Not required to have at least two dots. RFC 2965.
+ // A Set-Cookie2 with Domain=ajax.com will be accepted.
+
+ // domain must match host
+ if (!host.endsWith(domain)) {
+ if (domain.startsWith(".")) {
+ domain = domain.substring(1, domain.length());
+ }
+ if (!host.equals(domain)) {
+ throw new MalformedCookieException(
+ "Illegal domain attribute \"" + domain
+ + "\". Domain of origin: \"" + host + "\"");
+ }
+ }
+ } else {
+ if (!host.equals(domain)) {
+ throw new MalformedCookieException(
+ "Illegal domain attribute \"" + domain
+ + "\". Domain of origin: \"" + host + "\"");
+ }
+ }
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String host = origin.getHost();
+ String domain = cookie.getDomain();
+ if (domain == null) {
+ return false;
+ }
+ if (host.equals(domain)) {
+ return true;
+ }
+ if (!domain.startsWith(".")) {
+ domain = '.' + domain;
+ }
+ return host.endsWith(domain) || host.equals(domain.substring(1));
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BasicExpiresHandler.java b/src/org/apache/http/impl/cookie/BasicExpiresHandler.java
new file mode 100644
index 0000000..a53519e
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicExpiresHandler.java
@@ -0,0 +1,65 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java $
+ * $Revision: 558519 $
+ * $Date: 2007-07-22 11:19:49 -0700 (Sun, 22 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+
+public class BasicExpiresHandler extends AbstractCookieAttributeHandler {
+
+ /** Valid date patterns */
+ private final String[] datepatterns;
+
+ public BasicExpiresHandler(final String[] datepatterns) {
+ if (datepatterns == null) {
+ throw new IllegalArgumentException("Array of date patterns may not be null");
+ }
+ this.datepatterns = datepatterns;
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null) {
+ throw new MalformedCookieException("Missing value for expires attribute");
+ }
+ try {
+ cookie.setExpiryDate(DateUtils.parseDate(value, this.datepatterns));
+ } catch (DateParseException dpe) {
+ throw new MalformedCookieException("Unable to parse expires attribute: "
+ + value);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BasicMaxAgeHandler.java b/src/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
new file mode 100644
index 0000000..92a5c7d
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java $
+ * $Revision: 581953 $
+ * $Date: 2007-10-04 08:53:50 -0700 (Thu, 04 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import java.util.Date;
+
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler {
+
+ public BasicMaxAgeHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null) {
+ throw new MalformedCookieException("Missing value for max-age attribute");
+ }
+ int age;
+ try {
+ age = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new MalformedCookieException ("Invalid max-age attribute: "
+ + value);
+ }
+ if (age < 0) {
+ throw new MalformedCookieException ("Negative max-age attribute: "
+ + value);
+ }
+ cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BasicPathHandler.java b/src/org/apache/http/impl/cookie/BasicPathHandler.java
new file mode 100644
index 0000000..43a12c8
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicPathHandler.java
@@ -0,0 +1,91 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class BasicPathHandler implements CookieAttributeHandler {
+
+ public BasicPathHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null || value.trim().length() == 0) {
+ value = "/";
+ }
+ cookie.setPath(value);
+ }
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (!match(cookie, origin)) {
+ throw new MalformedCookieException(
+ "Illegal path attribute \"" + cookie.getPath()
+ + "\". Path of origin: \"" + origin.getPath() + "\"");
+ }
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String targetpath = origin.getPath();
+ String topmostPath = cookie.getPath();
+ if (topmostPath == null) {
+ topmostPath = "/";
+ }
+ if (topmostPath.length() > 1 && topmostPath.endsWith("/")) {
+ topmostPath = topmostPath.substring(0, topmostPath.length() - 1);
+ }
+ boolean match = targetpath.startsWith (topmostPath);
+ // if there is a match and these values are not exactly the same we have
+ // to make sure we're not matcing "/foobar" and "/foo"
+ if (match && targetpath.length() != topmostPath.length()) {
+ if (!topmostPath.endsWith("/")) {
+ match = (targetpath.charAt(topmostPath.length()) == '/');
+ }
+ }
+ return match;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BasicSecureHandler.java b/src/org/apache/http/impl/cookie/BasicSecureHandler.java
new file mode 100644
index 0000000..9100b9c
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BasicSecureHandler.java
@@ -0,0 +1,63 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class BasicSecureHandler extends AbstractCookieAttributeHandler {
+
+ public BasicSecureHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ cookie.setSecure(true);
+ }
+
+ @Override
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ return !cookie.isSecure() || origin.isSecure();
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BestMatchSpec.java b/src/org/apache/http/impl/cookie/BestMatchSpec.java
new file mode 100644
index 0000000..e33fec3
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BestMatchSpec.java
@@ -0,0 +1,186 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BestMatchSpec.java $
+ * $Revision: 657334 $
+ * $Date: 2008-05-17 04:44:16 -0700 (Sat, 17 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.List;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.MalformedCookieException;
+
+/**
+ * 'Meta' cookie specification that selects a cookie policy depending
+ * on the format of the cookie(s)
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class BestMatchSpec implements CookieSpec {
+
+ private final String[] datepatterns;
+ private final boolean oneHeader;
+
+ private RFC2965Spec strict;
+ private BrowserCompatSpec compat;
+ private NetscapeDraftSpec netscape;
+
+ public BestMatchSpec(final String[] datepatterns, boolean oneHeader) {
+ super();
+ this.datepatterns = datepatterns;
+ this.oneHeader = oneHeader;
+ }
+
+ public BestMatchSpec() {
+ this(null, false);
+ }
+
+ private RFC2965Spec getStrict() {
+ if (this.strict == null) {
+ this.strict = new RFC2965Spec(this.datepatterns, this.oneHeader);
+ }
+ return strict;
+ }
+
+ private BrowserCompatSpec getCompat() {
+ if (this.compat == null) {
+ this.compat = new BrowserCompatSpec(this.datepatterns);
+ }
+ return compat;
+ }
+
+ private NetscapeDraftSpec getNetscape() {
+ if (this.netscape == null) {
+ String[] patterns = this.datepatterns;
+ if (patterns == null) {
+ patterns = BrowserCompatSpec.DATE_PATTERNS;
+ }
+ this.netscape = new NetscapeDraftSpec(patterns);
+ }
+ return netscape;
+ }
+
+ public List<Cookie> parse(
+ final Header header,
+ final CookieOrigin origin) throws MalformedCookieException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ HeaderElement[] helems = header.getElements();
+ boolean versioned = false;
+ boolean netscape = false;
+ for (HeaderElement helem: helems) {
+ if (helem.getParameterByName("version") != null) {
+ versioned = true;
+ }
+ if (helem.getParameterByName("expires") != null) {
+ netscape = true;
+ }
+ }
+ if (netscape) {
+
+ }
+ // Do we have a cookie with a version attribute?
+ if (versioned) {
+ return getStrict().parse(helems, origin);
+ } else if (netscape) {
+ // Need to parse the header again,
+ // because Netscape draft cannot handle
+ // comma separators
+ return getNetscape().parse(header, origin);
+ } else {
+ return getCompat().parse(helems, origin);
+ }
+ }
+
+ public void validate(
+ final Cookie cookie,
+ final CookieOrigin origin) throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ if (cookie.getVersion() > 0) {
+ getStrict().validate(cookie, origin);
+ } else {
+ getCompat().validate(cookie, origin);
+ }
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ if (cookie.getVersion() > 0) {
+ return getStrict().match(cookie, origin);
+ } else {
+ return getCompat().match(cookie, origin);
+ }
+ }
+
+ public List<Header> formatCookies(final List<Cookie> cookies) {
+ if (cookies == null) {
+ throw new IllegalArgumentException("List of cookie may not be null");
+ }
+ int version = Integer.MAX_VALUE;
+ for (Cookie cookie: cookies) {
+ if (cookie.getVersion() < version) {
+ version = cookie.getVersion();
+ }
+ }
+ if (version > 0) {
+ return getStrict().formatCookies(cookies);
+ } else {
+ return getCompat().formatCookies(cookies);
+ }
+ }
+
+ public int getVersion() {
+ return getStrict().getVersion();
+ }
+
+ public Header getVersionHeader() {
+ return getStrict().getVersionHeader();
+ }
+
+} \ No newline at end of file
diff --git a/src/org/apache/http/impl/cookie/BestMatchSpecFactory.java b/src/org/apache/http/impl/cookie/BestMatchSpecFactory.java
new file mode 100644
index 0000000..cb632bb
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BestMatchSpecFactory.java
@@ -0,0 +1,57 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BestMatchSpecFactory.java $
+ * $Revision: 613707 $
+ * $Date: 2008-01-20 16:28:37 -0800 (Sun, 20 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecFactory;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class BestMatchSpecFactory implements CookieSpecFactory {
+
+ public CookieSpec newInstance(final HttpParams params) {
+ if (params != null) {
+ return new BestMatchSpec(
+ (String []) params.getParameter(CookieSpecPNames.DATE_PATTERNS),
+ params.getBooleanParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, false));
+ } else {
+ return new BestMatchSpec();
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BrowserCompatSpec.java b/src/org/apache/http/impl/cookie/BrowserCompatSpec.java
new file mode 100644
index 0000000..d7bc0da
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BrowserCompatSpec.java
@@ -0,0 +1,188 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpec.java $
+ * $Revision: 657334 $
+ * $Date: 2008-05-17 04:44:16 -0700 (Sat, 17 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Cookie specification that strives to closely mimic (mis)behavior of
+ * common web browser applications such as Microsoft Internet Explorer
+ * and Mozilla FireFox.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class BrowserCompatSpec extends CookieSpecBase {
+
+ /** Valid date patterns used per default */
+ protected static final String[] DATE_PATTERNS = new String[] {
+ DateUtils.PATTERN_RFC1123,
+ DateUtils.PATTERN_RFC1036,
+ DateUtils.PATTERN_ASCTIME,
+ "EEE, dd-MMM-yyyy HH:mm:ss z",
+ "EEE, dd-MMM-yyyy HH-mm-ss z",
+ "EEE, dd MMM yy HH:mm:ss z",
+ "EEE dd-MMM-yyyy HH:mm:ss z",
+ "EEE dd MMM yyyy HH:mm:ss z",
+ "EEE dd-MMM-yyyy HH-mm-ss z",
+ "EEE dd-MMM-yy HH:mm:ss z",
+ "EEE dd MMM yy HH:mm:ss z",
+ "EEE,dd-MMM-yy HH:mm:ss z",
+ "EEE,dd-MMM-yyyy HH:mm:ss z",
+ "EEE, dd-MM-yyyy HH:mm:ss z",
+ };
+
+ private final String[] datepatterns;
+
+ /** Default constructor */
+ public BrowserCompatSpec(final String[] datepatterns) {
+ super();
+ if (datepatterns != null) {
+ this.datepatterns = datepatterns.clone();
+ } else {
+ this.datepatterns = DATE_PATTERNS;
+ }
+ registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
+ registerAttribHandler(ClientCookie.DOMAIN_ATTR, new BasicDomainHandler());
+ registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
+ registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
+ registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
+ registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
+ this.datepatterns));
+ }
+
+ /** Default constructor */
+ public BrowserCompatSpec() {
+ this(null);
+ }
+
+ public List<Cookie> parse(final Header header, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String headervalue = header.getValue();
+ boolean isNetscapeCookie = false;
+ int i1 = headervalue.toLowerCase(Locale.ENGLISH).indexOf("expires=");
+ if (i1 != -1) {
+ i1 += "expires=".length();
+ int i2 = headervalue.indexOf(';', i1);
+ if (i2 == -1) {
+ i2 = headervalue.length();
+ }
+ try {
+ DateUtils.parseDate(headervalue.substring(i1, i2), this.datepatterns);
+ isNetscapeCookie = true;
+ } catch (DateParseException e) {
+ // Does not look like a valid expiry date
+ }
+ }
+ HeaderElement[] elems = null;
+ if (isNetscapeCookie) {
+ NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
+ CharArrayBuffer buffer;
+ ParserCursor cursor;
+ if (header instanceof FormattedHeader) {
+ buffer = ((FormattedHeader) header).getBuffer();
+ cursor = new ParserCursor(
+ ((FormattedHeader) header).getValuePos(),
+ buffer.length());
+ } else {
+ String s = header.getValue();
+ if (s == null) {
+ throw new MalformedCookieException("Header value is null");
+ }
+ buffer = new CharArrayBuffer(s.length());
+ buffer.append(s);
+ cursor = new ParserCursor(0, buffer.length());
+ }
+ elems = new HeaderElement[] { parser.parseHeader(buffer, cursor) };
+ } else {
+ elems = header.getElements();
+ }
+ return parse(elems, origin);
+ }
+
+ public List<Header> formatCookies(final List<Cookie> cookies) {
+ if (cookies == null) {
+ throw new IllegalArgumentException("List of cookies may not be null");
+ }
+ if (cookies.isEmpty()) {
+ throw new IllegalArgumentException("List of cookies may not be empty");
+ }
+ CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
+ buffer.append(SM.COOKIE);
+ buffer.append(": ");
+ for (int i = 0; i < cookies.size(); i++) {
+ Cookie cookie = cookies.get(i);
+ if (i > 0) {
+ buffer.append("; ");
+ }
+ buffer.append(cookie.getName());
+ buffer.append("=");
+ String s = cookie.getValue();
+ if (s != null) {
+ buffer.append(s);
+ }
+ }
+ List<Header> headers = new ArrayList<Header>(1);
+ headers.add(new BufferedHeader(buffer));
+ return headers;
+ }
+
+ public int getVersion() {
+ return 0;
+ }
+
+ public Header getVersionHeader() {
+ return null;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java b/src/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
new file mode 100644
index 0000000..71c0c05
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
@@ -0,0 +1,56 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java $
+ * $Revision: 576068 $
+ * $Date: 2007-09-16 03:25:01 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecFactory;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class BrowserCompatSpecFactory implements CookieSpecFactory {
+
+ public CookieSpec newInstance(final HttpParams params) {
+ if (params != null) {
+ return new BrowserCompatSpec(
+ (String []) params.getParameter(CookieSpecPNames.DATE_PATTERNS));
+ } else {
+ return new BrowserCompatSpec();
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/CookieSpecBase.java b/src/org/apache/http/impl/cookie/CookieSpecBase.java
new file mode 100644
index 0000000..8e70bb1
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/CookieSpecBase.java
@@ -0,0 +1,131 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/CookieSpecBase.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+
+/**
+ * Cookie management functions shared by all specification.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public abstract class CookieSpecBase extends AbstractCookieSpec {
+
+ protected static String getDefaultPath(final CookieOrigin origin) {
+ String defaultPath = origin.getPath();
+ int lastSlashIndex = defaultPath.lastIndexOf('/');
+ if (lastSlashIndex >= 0) {
+ if (lastSlashIndex == 0) {
+ //Do not remove the very first slash
+ lastSlashIndex = 1;
+ }
+ defaultPath = defaultPath.substring(0, lastSlashIndex);
+ }
+ return defaultPath;
+ }
+
+ protected static String getDefaultDomain(final CookieOrigin origin) {
+ return origin.getHost();
+ }
+
+ protected List<Cookie> parse(final HeaderElement[] elems, final CookieOrigin origin)
+ throws MalformedCookieException {
+ List<Cookie> cookies = new ArrayList<Cookie>(elems.length);
+ for (HeaderElement headerelement : elems) {
+ String name = headerelement.getName();
+ String value = headerelement.getValue();
+ if (name == null || name.length() == 0) {
+ throw new MalformedCookieException("Cookie name may not be empty");
+ }
+
+ BasicClientCookie cookie = new BasicClientCookie(name, value);
+ cookie.setPath(getDefaultPath(origin));
+ cookie.setDomain(getDefaultDomain(origin));
+
+ // cycle through the parameters
+ NameValuePair[] attribs = headerelement.getParameters();
+ for (int j = attribs.length - 1; j >= 0; j--) {
+ NameValuePair attrib = attribs[j];
+ String s = attrib.getName().toLowerCase(Locale.ENGLISH);
+
+ cookie.setAttribute(s, attrib.getValue());
+
+ CookieAttributeHandler handler = findAttribHandler(s);
+ if (handler != null) {
+ handler.parse(cookie, attrib.getValue());
+ }
+ }
+ cookies.add(cookie);
+ }
+ return cookies;
+ }
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ for (CookieAttributeHandler handler: getAttribHandlers()) {
+ handler.validate(cookie, origin);
+ }
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ for (CookieAttributeHandler handler: getAttribHandlers()) {
+ if (!handler.match(cookie, origin)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/DateParseException.java b/src/org/apache/http/impl/cookie/DateParseException.java
new file mode 100644
index 0000000..c80b669
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/DateParseException.java
@@ -0,0 +1,60 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/DateParseException.java $
+ * $Revision: 609105 $
+ * $Date: 2008-01-05 00:55:00 -0800 (Sat, 05 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+
+/**
+ * An exception to indicate an error parsing a date string.
+ *
+ * @see DateUtils
+ *
+ * @author Michael Becke
+ */
+public class DateParseException extends Exception {
+
+ private static final long serialVersionUID = 4417696455000643370L;
+
+ /**
+ *
+ */
+ public DateParseException() {
+ super();
+ }
+
+ /**
+ * @param message the exception message
+ */
+ public DateParseException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/DateUtils.java b/src/org/apache/http/impl/cookie/DateUtils.java
new file mode 100644
index 0000000..a0a056c
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/DateUtils.java
@@ -0,0 +1,261 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/DateUtils.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.lang.ref.SoftReference;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * A utility class for parsing and formatting HTTP dates as used in cookies and
+ * other headers. This class handles dates as defined by RFC 2616 section
+ * 3.3.1 as well as some other common non-standard formats.
+ *
+ * @author Christopher Brown
+ * @author Michael Becke
+ */
+public final class DateUtils {
+
+ /**
+ * Date format pattern used to parse HTTP date headers in RFC 1123 format.
+ */
+ public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+ /**
+ * Date format pattern used to parse HTTP date headers in RFC 1036 format.
+ */
+ public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
+
+ /**
+ * Date format pattern used to parse HTTP date headers in ANSI C
+ * <code>asctime()</code> format.
+ */
+ public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
+
+ private static final String[] DEFAULT_PATTERNS = new String[] {
+ PATTERN_RFC1036,
+ PATTERN_RFC1123,
+ PATTERN_ASCTIME
+ };
+
+ private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
+
+ public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+ static {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(GMT);
+ calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
+ }
+
+ /**
+ * Parses a date value. The formats used for parsing the date value are retrieved from
+ * the default http params.
+ *
+ * @param dateValue the date value to parse
+ *
+ * @return the parsed date
+ *
+ * @throws DateParseException if the value could not be parsed using any of the
+ * supported date formats
+ */
+ public static Date parseDate(String dateValue) throws DateParseException {
+ return parseDate(dateValue, null, null);
+ }
+
+ /**
+ * Parses the date value using the given date formats.
+ *
+ * @param dateValue the date value to parse
+ * @param dateFormats the date formats to use
+ *
+ * @return the parsed date
+ *
+ * @throws DateParseException if none of the dataFormats could parse the dateValue
+ */
+ public static Date parseDate(final String dateValue, String[] dateFormats)
+ throws DateParseException {
+ return parseDate(dateValue, dateFormats, null);
+ }
+
+ /**
+ * Parses the date value using the given date formats.
+ *
+ * @param dateValue the date value to parse
+ * @param dateFormats the date formats to use
+ * @param startDate During parsing, two digit years will be placed in the range
+ * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
+ * be <code>null</code>. When <code>null</code> is given as a parameter, year
+ * <code>2000</code> will be used.
+ *
+ * @return the parsed date
+ *
+ * @throws DateParseException if none of the dataFormats could parse the dateValue
+ */
+ public static Date parseDate(
+ String dateValue,
+ String[] dateFormats,
+ Date startDate
+ ) throws DateParseException {
+
+ if (dateValue == null) {
+ throw new IllegalArgumentException("dateValue is null");
+ }
+ if (dateFormats == null) {
+ dateFormats = DEFAULT_PATTERNS;
+ }
+ if (startDate == null) {
+ startDate = DEFAULT_TWO_DIGIT_YEAR_START;
+ }
+ // trim single quotes around date if present
+ // see issue #5279
+ if (dateValue.length() > 1
+ && dateValue.startsWith("'")
+ && dateValue.endsWith("'")
+ ) {
+ dateValue = dateValue.substring (1, dateValue.length() - 1);
+ }
+
+ for (String dateFormat : dateFormats) {
+ SimpleDateFormat dateParser = DateFormatHolder.formatFor(dateFormat);
+ dateParser.set2DigitYearStart(startDate);
+
+ try {
+ return dateParser.parse(dateValue);
+ } catch (ParseException pe) {
+ // ignore this exception, we will try the next format
+ }
+ }
+
+ // we were unable to parse the date
+ throw new DateParseException("Unable to parse the date " + dateValue);
+ }
+
+ /**
+ * Formats the given date according to the RFC 1123 pattern.
+ *
+ * @param date The date to format.
+ * @return An RFC 1123 formatted date string.
+ *
+ * @see #PATTERN_RFC1123
+ */
+ public static String formatDate(Date date) {
+ return formatDate(date, PATTERN_RFC1123);
+ }
+
+ /**
+ * Formats the given date according to the specified pattern. The pattern
+ * must conform to that used by the {@link SimpleDateFormat simple date
+ * format} class.
+ *
+ * @param date The date to format.
+ * @param pattern The pattern to use for formatting the date.
+ * @return A formatted date string.
+ *
+ * @throws IllegalArgumentException If the given date pattern is invalid.
+ *
+ * @see SimpleDateFormat
+ */
+ public static String formatDate(Date date, String pattern) {
+ if (date == null) throw new IllegalArgumentException("date is null");
+ if (pattern == null) throw new IllegalArgumentException("pattern is null");
+
+ SimpleDateFormat formatter = DateFormatHolder.formatFor(pattern);
+ return formatter.format(date);
+ }
+
+ /** This class should not be instantiated. */
+ private DateUtils() {
+ }
+
+ /**
+ * A factory for {@link SimpleDateFormat}s. The instances are stored in a
+ * threadlocal way because SimpleDateFormat is not threadsafe as noted in
+ * {@link SimpleDateFormat its javadoc}.
+ *
+ * @author Daniel Mueller
+ */
+ final static class DateFormatHolder {
+
+ private static final ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>
+ THREADLOCAL_FORMATS = new ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>() {
+
+ @Override
+ protected SoftReference<Map<String, SimpleDateFormat>> initialValue() {
+ return new SoftReference<Map<String, SimpleDateFormat>>(
+ new HashMap<String, SimpleDateFormat>());
+ }
+
+ };
+
+ /**
+ * creates a {@link SimpleDateFormat} for the requested format string.
+ *
+ * @param pattern
+ * a non-<code>null</code> format String according to
+ * {@link SimpleDateFormat}. The format is not checked against
+ * <code>null</code> since all paths go through
+ * {@link DateUtils}.
+ * @return the requested format. This simple dateformat should not be used
+ * to {@link SimpleDateFormat#applyPattern(String) apply} to a
+ * different pattern.
+ */
+ public static SimpleDateFormat formatFor(String pattern) {
+ SoftReference<Map<String, SimpleDateFormat>> ref = THREADLOCAL_FORMATS.get();
+ Map<String, SimpleDateFormat> formats = ref.get();
+ if (formats == null) {
+ formats = new HashMap<String, SimpleDateFormat>();
+ THREADLOCAL_FORMATS.set(
+ new SoftReference<Map<String, SimpleDateFormat>>(formats));
+ }
+
+ SimpleDateFormat format = formats.get(pattern);
+ if (format == null) {
+ format = new SimpleDateFormat(pattern, Locale.US);
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ formats.put(pattern, format);
+ }
+
+ return format;
+ }
+
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/NetscapeDomainHandler.java b/src/org/apache/http/impl/cookie/NetscapeDomainHandler.java
new file mode 100644
index 0000000..8b785ae
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/NetscapeDomainHandler.java
@@ -0,0 +1,106 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+
+public class NetscapeDomainHandler extends BasicDomainHandler {
+
+ public NetscapeDomainHandler() {
+ super();
+ }
+
+ @Override
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ super.validate(cookie, origin);
+ // Perform Netscape Cookie draft specific validation
+ String host = origin.getHost();
+ String domain = cookie.getDomain();
+ if (host.contains(".")) {
+ int domainParts = new StringTokenizer(domain, ".").countTokens();
+
+ if (isSpecialDomain(domain)) {
+ if (domainParts < 2) {
+ throw new MalformedCookieException("Domain attribute \""
+ + domain
+ + "\" violates the Netscape cookie specification for "
+ + "special domains");
+ }
+ } else {
+ if (domainParts < 3) {
+ throw new MalformedCookieException("Domain attribute \""
+ + domain
+ + "\" violates the Netscape cookie specification");
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the given domain is in one of the seven special
+ * top level domains defined by the Netscape cookie specification.
+ * @param domain The domain.
+ * @return True if the specified domain is "special"
+ */
+ private static boolean isSpecialDomain(final String domain) {
+ final String ucDomain = domain.toUpperCase(Locale.ENGLISH);
+ return ucDomain.endsWith(".COM")
+ || ucDomain.endsWith(".EDU")
+ || ucDomain.endsWith(".NET")
+ || ucDomain.endsWith(".GOV")
+ || ucDomain.endsWith(".MIL")
+ || ucDomain.endsWith(".ORG")
+ || ucDomain.endsWith(".INT");
+ }
+
+ @Override
+public boolean match(Cookie cookie, CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String host = origin.getHost();
+ String domain = cookie.getDomain();
+ if (domain == null) {
+ return false;
+ }
+ return host.endsWith(domain);
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java b/src/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java
new file mode 100644
index 0000000..ca6b7fa
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java
@@ -0,0 +1,78 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java $
+ * $Revision: 603563 $
+ * $Date: 2007-12-12 03:17:55 -0800 (Wed, 12 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.message.BasicHeaderElement;
+import org.apache.http.message.BasicHeaderValueParser;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.util.CharArrayBuffer;
+
+public class NetscapeDraftHeaderParser {
+
+ public final static NetscapeDraftHeaderParser DEFAULT = new NetscapeDraftHeaderParser();
+
+ private final static char[] DELIMITERS = new char[] { ';' };
+
+ private final BasicHeaderValueParser nvpParser;
+
+ public NetscapeDraftHeaderParser() {
+ super();
+ this.nvpParser = BasicHeaderValueParser.DEFAULT;
+ }
+
+ public HeaderElement parseHeader(
+ final CharArrayBuffer buffer,
+ final ParserCursor cursor) throws ParseException {
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+ NameValuePair nvp = this.nvpParser.parseNameValuePair(buffer, cursor, DELIMITERS);
+ List<NameValuePair> params = new ArrayList<NameValuePair>();
+ while (!cursor.atEnd()) {
+ NameValuePair param = this.nvpParser.parseNameValuePair(buffer, cursor, DELIMITERS);
+ params.add(param);
+ }
+ return new BasicHeaderElement(
+ nvp.getName(),
+ nvp.getValue(), params.toArray(new NameValuePair[params.size()]));
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/NetscapeDraftSpec.java b/src/org/apache/http/impl/cookie/NetscapeDraftSpec.java
new file mode 100644
index 0000000..3bc4f9f
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/NetscapeDraftSpec.java
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpec.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Netscape cookie draft compliant cookie policy
+ *
+ * @author B.C. Holmes
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
+ * @author Rod Waldhoff
+ * @author dIon Gillard
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
+ * @author Marc A. Saegesser
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @since 4.0
+ */
+public class NetscapeDraftSpec extends CookieSpecBase {
+
+ protected static final String EXPIRES_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
+
+ private final String[] datepatterns;
+
+ /** Default constructor */
+ public NetscapeDraftSpec(final String[] datepatterns) {
+ super();
+ if (datepatterns != null) {
+ this.datepatterns = datepatterns.clone();
+ } else {
+ this.datepatterns = new String[] { EXPIRES_PATTERN };
+ }
+ registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
+ registerAttribHandler(ClientCookie.DOMAIN_ATTR, new NetscapeDomainHandler());
+ registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
+ registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
+ registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
+ registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
+ this.datepatterns));
+ }
+
+ /** Default constructor */
+ public NetscapeDraftSpec() {
+ this(null);
+ }
+
+ /**
+ * Parses the Set-Cookie value into an array of <tt>Cookie</tt>s.
+ *
+ * <p>Syntax of the Set-Cookie HTTP Response Header:</p>
+ *
+ * <p>This is the format a CGI script would use to add to
+ * the HTTP headers a new piece of data which is to be stored by
+ * the client for later retrieval.</p>
+ *
+ * <PRE>
+ * Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
+ * </PRE>
+ *
+ * <p>Please note that Netscape draft specification does not fully
+ * conform to the HTTP header format. Netscape draft does not specify
+ * whether multiple cookies may be sent in one header. Hence, comma
+ * character may be present in unquoted cookie value or unquoted
+ * parameter value.</p>
+ *
+ * @see <a href="http://wp.netscape.com/newsref/std/cookie_spec.html">
+ * The Cookie Spec.</a>
+ *
+ * @param header the <tt>Set-Cookie</tt> received from the server
+ * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie value
+ * @throws MalformedCookieException if an exception occurs during parsing
+ */
+ public List<Cookie> parse(final Header header, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
+ CharArrayBuffer buffer;
+ ParserCursor cursor;
+ if (header instanceof FormattedHeader) {
+ buffer = ((FormattedHeader) header).getBuffer();
+ cursor = new ParserCursor(
+ ((FormattedHeader) header).getValuePos(),
+ buffer.length());
+ } else {
+ String s = header.getValue();
+ if (s == null) {
+ throw new MalformedCookieException("Header value is null");
+ }
+ buffer = new CharArrayBuffer(s.length());
+ buffer.append(s);
+ cursor = new ParserCursor(0, buffer.length());
+ }
+ return parse(new HeaderElement[] { parser.parseHeader(buffer, cursor) }, origin);
+ }
+
+ public List<Header> formatCookies(final List<Cookie> cookies) {
+ if (cookies == null) {
+ throw new IllegalArgumentException("List of cookies may not be null");
+ }
+ if (cookies.isEmpty()) {
+ throw new IllegalArgumentException("List of cookies may not be empty");
+ }
+ CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
+ buffer.append(SM.COOKIE);
+ buffer.append(": ");
+ for (int i = 0; i < cookies.size(); i++) {
+ Cookie cookie = cookies.get(i);
+ if (i > 0) {
+ buffer.append("; ");
+ }
+ buffer.append(cookie.getName());
+ String s = cookie.getValue();
+ if (s != null) {
+ buffer.append("=");
+ buffer.append(s);
+ }
+ }
+ List<Header> headers = new ArrayList<Header>(1);
+ headers.add(new BufferedHeader(buffer));
+ return headers;
+ }
+
+ public int getVersion() {
+ return 0;
+ }
+
+ public Header getVersionHeader() {
+ return null;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java b/src/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
new file mode 100644
index 0000000..0dcb187
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
@@ -0,0 +1,56 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java $
+ * $Revision: 657334 $
+ * $Date: 2008-05-17 04:44:16 -0700 (Sat, 17 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecFactory;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class NetscapeDraftSpecFactory implements CookieSpecFactory {
+
+ public CookieSpec newInstance(final HttpParams params) {
+ if (params != null) {
+ return new NetscapeDraftSpec(
+ (String []) params.getParameter(CookieSpecPNames.DATE_PATTERNS));
+ } else {
+ return new NetscapeDraftSpec();
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2109DomainHandler.java b/src/org/apache/http/impl/cookie/RFC2109DomainHandler.java
new file mode 100644
index 0000000..9cfd484
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2109DomainHandler.java
@@ -0,0 +1,126 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109DomainHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import java.util.Locale;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class RFC2109DomainHandler implements CookieAttributeHandler {
+
+ public RFC2109DomainHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null) {
+ throw new MalformedCookieException("Missing value for domain attribute");
+ }
+ if (value.trim().length() == 0) {
+ throw new MalformedCookieException("Blank value for domain attribute");
+ }
+ cookie.setDomain(value);
+ }
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String host = origin.getHost();
+ String domain = cookie.getDomain();
+ if (domain == null) {
+ throw new MalformedCookieException("Cookie domain may not be null");
+ }
+ if (!domain.equals(host)) {
+ int dotIndex = domain.indexOf('.');
+ if (dotIndex == -1) {
+ throw new MalformedCookieException("Domain attribute \""
+ + domain
+ + "\" does not match the host \""
+ + host + "\"");
+ }
+ // domain must start with dot
+ if (!domain.startsWith(".")) {
+ throw new MalformedCookieException("Domain attribute \""
+ + domain
+ + "\" violates RFC 2109: domain must start with a dot");
+ }
+ // domain must have at least one embedded dot
+ dotIndex = domain.indexOf('.', 1);
+ if (dotIndex < 0 || dotIndex == domain.length() - 1) {
+ throw new MalformedCookieException("Domain attribute \""
+ + domain
+ + "\" violates RFC 2109: domain must contain an embedded dot");
+ }
+ host = host.toLowerCase(Locale.ENGLISH);
+ if (!host.endsWith(domain)) {
+ throw new MalformedCookieException(
+ "Illegal domain attribute \"" + domain
+ + "\". Domain of origin: \"" + host + "\"");
+ }
+ // host minus domain may not contain any dots
+ String hostWithoutDomain = host.substring(0, host.length() - domain.length());
+ if (hostWithoutDomain.indexOf('.') != -1) {
+ throw new MalformedCookieException("Domain attribute \""
+ + domain
+ + "\" violates RFC 2109: host minus domain may not contain any dots");
+ }
+ }
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String host = origin.getHost();
+ String domain = cookie.getDomain();
+ if (domain == null) {
+ return false;
+ }
+ return host.equals(domain) || (domain.startsWith(".") && host.endsWith(domain));
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2109Spec.java b/src/org/apache/http/impl/cookie/RFC2109Spec.java
new file mode 100644
index 0000000..9e45408
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2109Spec.java
@@ -0,0 +1,246 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java $
+ * $Revision: 677240 $
+ * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookiePathComparator;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * RFC 2109 compliant cookie policy
+ *
+ * @author B.C. Holmes
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
+ * @author Rod Waldhoff
+ * @author dIon Gillard
+ * @author Sean C. Sullivan
+ * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
+ * @author Marc A. Saegesser
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @since 4.0
+ */
+
+public class RFC2109Spec extends CookieSpecBase {
+
+ private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
+
+ private final static String[] DATE_PATTERNS = {
+ DateUtils.PATTERN_RFC1123,
+ DateUtils.PATTERN_RFC1036,
+ DateUtils.PATTERN_ASCTIME
+ };
+
+ private final String[] datepatterns;
+ private final boolean oneHeader;
+
+ /** Default constructor */
+ public RFC2109Spec(final String[] datepatterns, boolean oneHeader) {
+ super();
+ if (datepatterns != null) {
+ this.datepatterns = datepatterns.clone();
+ } else {
+ this.datepatterns = DATE_PATTERNS;
+ }
+ this.oneHeader = oneHeader;
+ registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2109VersionHandler());
+ registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
+ registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2109DomainHandler());
+ registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
+ registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
+ registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
+ registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
+ this.datepatterns));
+ }
+
+ /** Default constructor */
+ public RFC2109Spec() {
+ this(null, false);
+ }
+
+ public List<Cookie> parse(final Header header, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ HeaderElement[] elems = header.getElements();
+ return parse(elems, origin);
+ }
+
+ @Override
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ String name = cookie.getName();
+ if (name.indexOf(' ') != -1) {
+ throw new MalformedCookieException("Cookie name may not contain blanks");
+ }
+ if (name.startsWith("$")) {
+ throw new MalformedCookieException("Cookie name may not start with $");
+ }
+ super.validate(cookie, origin);
+ }
+
+ public List<Header> formatCookies(List<Cookie> cookies) {
+ if (cookies == null) {
+ throw new IllegalArgumentException("List of cookies may not be null");
+ }
+ if (cookies.isEmpty()) {
+ throw new IllegalArgumentException("List of cookies may not be empty");
+ }
+ if (cookies.size() > 1) {
+ // Create a mutable copy and sort the copy.
+ cookies = new ArrayList<Cookie>(cookies);
+ Collections.sort(cookies, PATH_COMPARATOR);
+ }
+ if (this.oneHeader) {
+ return doFormatOneHeader(cookies);
+ } else {
+ return doFormatManyHeaders(cookies);
+ }
+ }
+
+ private List<Header> doFormatOneHeader(final List<Cookie> cookies) {
+ int version = Integer.MAX_VALUE;
+ // Pick the lowest common denominator
+ for (Cookie cookie : cookies) {
+ if (cookie.getVersion() < version) {
+ version = cookie.getVersion();
+ }
+ }
+ CharArrayBuffer buffer = new CharArrayBuffer(40 * cookies.size());
+ buffer.append(SM.COOKIE);
+ buffer.append(": ");
+ buffer.append("$Version=");
+ buffer.append(Integer.toString(version));
+ for (Cookie cooky : cookies) {
+ buffer.append("; ");
+ Cookie cookie = cooky;
+ formatCookieAsVer(buffer, cookie, version);
+ }
+ List<Header> headers = new ArrayList<Header>(1);
+ headers.add(new BufferedHeader(buffer));
+ return headers;
+ }
+
+ private List<Header> doFormatManyHeaders(final List<Cookie> cookies) {
+ List<Header> headers = new ArrayList<Header>(cookies.size());
+ for (Cookie cookie : cookies) {
+ int version = cookie.getVersion();
+ CharArrayBuffer buffer = new CharArrayBuffer(40);
+ buffer.append("Cookie: ");
+ buffer.append("$Version=");
+ buffer.append(Integer.toString(version));
+ buffer.append("; ");
+ formatCookieAsVer(buffer, cookie, version);
+ headers.add(new BufferedHeader(buffer));
+ }
+ return headers;
+ }
+
+ /**
+ * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
+ * header as defined in RFC 2109 for backward compatibility with cookie
+ * version 0
+ * @param buffer The char array buffer to use for output
+ * @param name The cookie name
+ * @param value The cookie value
+ * @param version The cookie version
+ */
+ protected void formatParamAsVer(final CharArrayBuffer buffer,
+ final String name, final String value, int version) {
+ buffer.append(name);
+ buffer.append("=");
+ if (value != null) {
+ if (version > 0) {
+ buffer.append('\"');
+ buffer.append(value);
+ buffer.append('\"');
+ } else {
+ buffer.append(value);
+ }
+ }
+ }
+
+ /**
+ * Return a string suitable for sending in a <tt>"Cookie"</tt> header
+ * as defined in RFC 2109 for backward compatibility with cookie version 0
+ * @param buffer The char array buffer to use for output
+ * @param cookie The {@link Cookie} to be formatted as string
+ * @param version The version to use.
+ */
+ protected void formatCookieAsVer(final CharArrayBuffer buffer,
+ final Cookie cookie, int version) {
+ formatParamAsVer(buffer, cookie.getName(), cookie.getValue(), version);
+ if (cookie.getPath() != null) {
+ if (cookie instanceof ClientCookie
+ && ((ClientCookie) cookie).containsAttribute(ClientCookie.PATH_ATTR)) {
+ buffer.append("; ");
+ formatParamAsVer(buffer, "$Path", cookie.getPath(), version);
+ }
+ }
+ if (cookie.getDomain() != null) {
+ if (cookie instanceof ClientCookie
+ && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
+ buffer.append("; ");
+ formatParamAsVer(buffer, "$Domain", cookie.getDomain(), version);
+ }
+ }
+ }
+
+ public int getVersion() {
+ return 1;
+ }
+
+ public Header getVersionHeader() {
+ return null;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2109SpecFactory.java b/src/org/apache/http/impl/cookie/RFC2109SpecFactory.java
new file mode 100644
index 0000000..35c506e
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2109SpecFactory.java
@@ -0,0 +1,57 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109SpecFactory.java $
+ * $Revision: 576068 $
+ * $Date: 2007-09-16 03:25:01 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecFactory;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class RFC2109SpecFactory implements CookieSpecFactory {
+
+ public CookieSpec newInstance(final HttpParams params) {
+ if (params != null) {
+ return new RFC2109Spec(
+ (String []) params.getParameter(CookieSpecPNames.DATE_PATTERNS),
+ params.getBooleanParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, false));
+ } else {
+ return new RFC2109Spec();
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2109VersionHandler.java b/src/org/apache/http/impl/cookie/RFC2109VersionHandler.java
new file mode 100644
index 0000000..d2c4955
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2109VersionHandler.java
@@ -0,0 +1,74 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109VersionHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+public class RFC2109VersionHandler extends AbstractCookieAttributeHandler {
+
+ public RFC2109VersionHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null) {
+ throw new MalformedCookieException("Missing value for version attribute");
+ }
+ if (value.trim().length() == 0) {
+ throw new MalformedCookieException("Blank value for version attribute");
+ }
+ try {
+ cookie.setVersion(Integer.parseInt(value));
+ } catch (NumberFormatException e) {
+ throw new MalformedCookieException("Invalid version: "
+ + e.getMessage());
+ }
+ }
+
+ @Override
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (cookie.getVersion() < 0) {
+ throw new MalformedCookieException("Cookie version may not be negative");
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java b/src/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java
new file mode 100644
index 0000000..aa3a1c5
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java $
+ * $Revision: 590695 $
+ * $Date: 2007-10-31 07:55:41 -0700 (Wed, 31 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.cookie.SetCookie2;
+
+/**
+ * <tt>"CommantURL"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ */
+ public class RFC2965CommentUrlAttributeHandler implements CookieAttributeHandler {
+
+ public RFC2965CommentUrlAttributeHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String commenturl)
+ throws MalformedCookieException {
+ if (cookie instanceof SetCookie2) {
+ SetCookie2 cookie2 = (SetCookie2) cookie;
+ cookie2.setCommentURL(commenturl);
+ }
+ }
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ return true;
+ }
+
+ } \ No newline at end of file
diff --git a/src/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java b/src/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java
new file mode 100644
index 0000000..aa81145
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java
@@ -0,0 +1,66 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java $
+ * $Revision: 590695 $
+ * $Date: 2007-10-31 07:55:41 -0700 (Wed, 31 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.cookie.SetCookie2;
+
+/**
+ * <tt>"Discard"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ */
+ public class RFC2965DiscardAttributeHandler implements CookieAttributeHandler {
+
+ public RFC2965DiscardAttributeHandler() {
+ super();
+ }
+
+ public void parse(final SetCookie cookie, final String commenturl)
+ throws MalformedCookieException {
+ if (cookie instanceof SetCookie2) {
+ SetCookie2 cookie2 = (SetCookie2) cookie;
+ cookie2.setDiscard(true);
+ }
+ }
+
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ return true;
+ }
+
+ } \ No newline at end of file
diff --git a/src/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java b/src/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java
new file mode 100644
index 0000000..b07e5e9
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java
@@ -0,0 +1,195 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.Locale;
+
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+
+/**
+ * <tt>"Domain"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ *
+ * @author jain.samit@gmail.com (Samit Jain)
+ *
+ * @since 3.1
+ */
+public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
+
+ public RFC2965DomainAttributeHandler() {
+ super();
+ }
+
+ /**
+ * Parse cookie domain attribute.
+ */
+ public void parse(final SetCookie cookie, String domain)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (domain == null) {
+ throw new MalformedCookieException(
+ "Missing value for domain attribute");
+ }
+ if (domain.trim().length() == 0) {
+ throw new MalformedCookieException(
+ "Blank value for domain attribute");
+ }
+ domain = domain.toLowerCase(Locale.ENGLISH);
+ if (!domain.startsWith(".")) {
+ // Per RFC 2965 section 3.2.2
+ // "... If an explicitly specified value does not start with
+ // a dot, the user agent supplies a leading dot ..."
+ // That effectively implies that the domain attribute
+ // MAY NOT be an IP address of a host name
+ domain = '.' + domain;
+ }
+ cookie.setDomain(domain);
+ }
+
+ /**
+ * Performs domain-match as defined by the RFC2965.
+ * <p>
+ * Host A's name domain-matches host B's if
+ * <ol>
+ * <ul>their host name strings string-compare equal; or</ul>
+ * <ul>A is a HDN string and has the form NB, where N is a non-empty
+ * name string, B has the form .B', and B' is a HDN string. (So,
+ * x.y.com domain-matches .Y.com but not Y.com.)</ul>
+ * </ol>
+ *
+ * @param host host name where cookie is received from or being sent to.
+ * @param domain The cookie domain attribute.
+ * @return true if the specified host matches the given domain.
+ */
+ public boolean domainMatch(String host, String domain) {
+ boolean match = host.equals(domain)
+ || (domain.startsWith(".") && host.endsWith(domain));
+
+ return match;
+ }
+
+ /**
+ * Validate cookie domain attribute.
+ */
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String host = origin.getHost().toLowerCase(Locale.ENGLISH);
+ if (cookie.getDomain() == null) {
+ throw new MalformedCookieException("Invalid cookie state: " +
+ "domain not specified");
+ }
+ String cookieDomain = cookie.getDomain().toLowerCase(Locale.ENGLISH);
+
+ if (cookie instanceof ClientCookie
+ && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
+ // Domain attribute must start with a dot
+ if (!cookieDomain.startsWith(".")) {
+ throw new MalformedCookieException("Domain attribute \"" +
+ cookie.getDomain() + "\" violates RFC 2109: domain must start with a dot");
+ }
+
+ // Domain attribute must contain at least one embedded dot,
+ // or the value must be equal to .local.
+ int dotIndex = cookieDomain.indexOf('.', 1);
+ if (((dotIndex < 0) || (dotIndex == cookieDomain.length() - 1))
+ && (!cookieDomain.equals(".local"))) {
+ throw new MalformedCookieException(
+ "Domain attribute \"" + cookie.getDomain()
+ + "\" violates RFC 2965: the value contains no embedded dots "
+ + "and the value is not .local");
+ }
+
+ // The effective host name must domain-match domain attribute.
+ if (!domainMatch(host, cookieDomain)) {
+ throw new MalformedCookieException(
+ "Domain attribute \"" + cookie.getDomain()
+ + "\" violates RFC 2965: effective host name does not "
+ + "domain-match domain attribute.");
+ }
+
+ // effective host name minus domain must not contain any dots
+ String effectiveHostWithoutDomain = host.substring(
+ 0, host.length() - cookieDomain.length());
+ if (effectiveHostWithoutDomain.indexOf('.') != -1) {
+ throw new MalformedCookieException("Domain attribute \""
+ + cookie.getDomain() + "\" violates RFC 2965: "
+ + "effective host minus domain may not contain any dots");
+ }
+ } else {
+ // Domain was not specified in header. In this case, domain must
+ // string match request host (case-insensitive).
+ if (!cookie.getDomain().equals(host)) {
+ throw new MalformedCookieException("Illegal domain attribute: \""
+ + cookie.getDomain() + "\"."
+ + "Domain of origin: \""
+ + host + "\"");
+ }
+ }
+ }
+
+ /**
+ * Match cookie domain attribute.
+ */
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ String host = origin.getHost().toLowerCase(Locale.ENGLISH);
+ String cookieDomain = cookie.getDomain();
+
+ // The effective host name MUST domain-match the Domain
+ // attribute of the cookie.
+ if (!domainMatch(host, cookieDomain)) {
+ return false;
+ }
+ // effective host name minus domain must not contain any dots
+ String effectiveHostWithoutDomain = host.substring(
+ 0, host.length() - cookieDomain.length());
+ return effectiveHostWithoutDomain.indexOf('.') == -1;
+ }
+
+} \ No newline at end of file
diff --git a/src/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java b/src/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
new file mode 100644
index 0000000..b881cda
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
@@ -0,0 +1,168 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java $
+ * $Revision: 590695 $
+ * $Date: 2007-10-31 07:55:41 -0700 (Wed, 31 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.StringTokenizer;
+
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.cookie.SetCookie2;
+
+/**
+ * <tt>"Port"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ */
+public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
+
+ public RFC2965PortAttributeHandler() {
+ super();
+ }
+
+ /**
+ * Parses the given Port attribute value (e.g. "8000,8001,8002")
+ * into an array of ports.
+ *
+ * @param portValue port attribute value
+ * @return parsed array of ports
+ * @throws MalformedCookieException if there is a problem in
+ * parsing due to invalid portValue.
+ */
+ private static int[] parsePortAttribute(final String portValue)
+ throws MalformedCookieException {
+ StringTokenizer st = new StringTokenizer(portValue, ",");
+ int[] ports = new int[st.countTokens()];
+ try {
+ int i = 0;
+ while(st.hasMoreTokens()) {
+ ports[i] = Integer.parseInt(st.nextToken().trim());
+ if (ports[i] < 0) {
+ throw new MalformedCookieException ("Invalid Port attribute.");
+ }
+ ++i;
+ }
+ } catch (NumberFormatException e) {
+ throw new MalformedCookieException ("Invalid Port "
+ + "attribute: " + e.getMessage());
+ }
+ return ports;
+ }
+
+ /**
+ * Returns <tt>true</tt> if the given port exists in the given
+ * ports list.
+ *
+ * @param port port of host where cookie was received from or being sent to.
+ * @param ports port list
+ * @return true returns <tt>true</tt> if the given port exists in
+ * the given ports list; <tt>false</tt> otherwise.
+ */
+ private static boolean portMatch(int port, int[] ports) {
+ boolean portInList = false;
+ for (int i = 0, len = ports.length; i < len; i++) {
+ if (port == ports[i]) {
+ portInList = true;
+ break;
+ }
+ }
+ return portInList;
+ }
+
+ /**
+ * Parse cookie port attribute.
+ */
+ public void parse(final SetCookie cookie, final String portValue)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (cookie instanceof SetCookie2) {
+ SetCookie2 cookie2 = (SetCookie2) cookie;
+ if (portValue != null && portValue.trim().length() > 0) {
+ int[] ports = parsePortAttribute(portValue);
+ cookie2.setPorts(ports);
+ }
+ }
+ }
+
+ /**
+ * Validate cookie port attribute. If the Port attribute was specified
+ * in header, the request port must be in cookie's port list.
+ */
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ int port = origin.getPort();
+ if (cookie instanceof ClientCookie
+ && ((ClientCookie) cookie).containsAttribute(ClientCookie.PORT_ATTR)) {
+ if (!portMatch(port, cookie.getPorts())) {
+ throw new MalformedCookieException(
+ "Port attribute violates RFC 2965: "
+ + "Request port not found in cookie's port list.");
+ }
+ }
+ }
+
+ /**
+ * Match cookie port attribute. If the Port attribute is not specified
+ * in header, the cookie can be sent to any port. Otherwise, the request port
+ * must be in the cookie's port list.
+ */
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ int port = origin.getPort();
+ if (cookie instanceof ClientCookie
+ && ((ClientCookie) cookie).containsAttribute(ClientCookie.PORT_ATTR)) {
+ if (cookie.getPorts() == null) {
+ // Invalid cookie state: port not specified
+ return false;
+ }
+ if (!portMatch(port, cookie.getPorts())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2965Spec.java b/src/org/apache/http/impl/cookie/RFC2965Spec.java
new file mode 100644
index 0000000..9422fdf
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965Spec.java
@@ -0,0 +1,259 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * <p>RFC 2965 specific cookie management functions.</p>
+ *
+ * @author jain.samit@gmail.com (Samit Jain)
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 3.1
+ */
+public class RFC2965Spec extends RFC2109Spec {
+
+ /**
+ * Default constructor
+ *
+ */
+ public RFC2965Spec() {
+ this(null, false);
+ }
+
+ public RFC2965Spec(final String[] datepatterns, boolean oneHeader) {
+ super(datepatterns, oneHeader);
+ registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2965DomainAttributeHandler());
+ registerAttribHandler(ClientCookie.PORT_ATTR, new RFC2965PortAttributeHandler());
+ registerAttribHandler(ClientCookie.COMMENTURL_ATTR, new RFC2965CommentUrlAttributeHandler());
+ registerAttribHandler(ClientCookie.DISCARD_ATTR, new RFC2965DiscardAttributeHandler());
+ registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2965VersionAttributeHandler());
+ }
+
+ private BasicClientCookie createCookie(
+ final String name, final String value, final CookieOrigin origin) {
+ BasicClientCookie cookie = new BasicClientCookie(name, value);
+ cookie.setPath(getDefaultPath(origin));
+ cookie.setDomain(getDefaultDomain(origin));
+ return cookie;
+ }
+
+ private BasicClientCookie createCookie2(
+ final String name, final String value, final CookieOrigin origin) {
+ BasicClientCookie2 cookie = new BasicClientCookie2(name, value);
+ cookie.setPath(getDefaultPath(origin));
+ cookie.setDomain(getDefaultDomain(origin));
+ cookie.setPorts(new int [] { origin.getPort() });
+ return cookie;
+ }
+
+ @Override
+ public List<Cookie> parse(
+ final Header header,
+ CookieOrigin origin) throws MalformedCookieException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+
+ origin = adjustEffectiveHost(origin);
+
+ HeaderElement[] elems = header.getElements();
+
+ List<Cookie> cookies = new ArrayList<Cookie>(elems.length);
+ for (HeaderElement headerelement : elems) {
+ String name = headerelement.getName();
+ String value = headerelement.getValue();
+ if (name == null || name.length() == 0) {
+ throw new MalformedCookieException("Cookie name may not be empty");
+ }
+
+ BasicClientCookie cookie;
+ if (header.getName().equals(SM.SET_COOKIE2)) {
+ cookie = createCookie2(name, value, origin);
+ } else {
+ cookie = createCookie(name, value, origin);
+ }
+
+ // cycle through the parameters
+ NameValuePair[] attribs = headerelement.getParameters();
+
+ // Eliminate duplicate attributes. The first occurrence takes precedence
+ // See RFC2965: 3.2 Origin Server Role
+ Map<String, NameValuePair> attribmap =
+ new HashMap<String, NameValuePair>(attribs.length);
+ for (int j = attribs.length - 1; j >= 0; j--) {
+ NameValuePair param = attribs[j];
+ attribmap.put(param.getName().toLowerCase(Locale.ENGLISH), param);
+ }
+ for (Map.Entry<String, NameValuePair> entry : attribmap.entrySet()) {
+ NameValuePair attrib = entry.getValue();
+ String s = attrib.getName().toLowerCase(Locale.ENGLISH);
+
+ cookie.setAttribute(s, attrib.getValue());
+
+ CookieAttributeHandler handler = findAttribHandler(s);
+ if (handler != null) {
+ handler.parse(cookie, attrib.getValue());
+ }
+ }
+ cookies.add(cookie);
+ }
+ return cookies;
+ }
+
+ @Override
+ public void validate(final Cookie cookie, CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ origin = adjustEffectiveHost(origin);
+ super.validate(cookie, origin);
+ }
+
+ @Override
+ public boolean match(final Cookie cookie, CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ origin = adjustEffectiveHost(origin);
+ return super.match(cookie, origin);
+ }
+
+ /**
+ * Adds valid Port attribute value, e.g. "8000,8001,8002"
+ */
+ @Override
+ protected void formatCookieAsVer(final CharArrayBuffer buffer,
+ final Cookie cookie, int version) {
+ super.formatCookieAsVer(buffer, cookie, version);
+ // format port attribute
+ if (cookie instanceof ClientCookie) {
+ // Test if the port attribute as set by the origin server is not blank
+ String s = ((ClientCookie) cookie).getAttribute(ClientCookie.PORT_ATTR);
+ if (s != null) {
+ buffer.append("; $Port");
+ buffer.append("=\"");
+ if (s.trim().length() > 0) {
+ int[] ports = cookie.getPorts();
+ if (ports != null) {
+ for (int i = 0, len = ports.length; i < len; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(Integer.toString(ports[i]));
+ }
+ }
+ }
+ buffer.append("\"");
+ }
+ }
+ }
+
+ /**
+ * Set 'effective host name' as defined in RFC 2965.
+ * <p>
+ * If a host name contains no dots, the effective host name is
+ * that name with the string .local appended to it. Otherwise
+ * the effective host name is the same as the host name. Note
+ * that all effective host names contain at least one dot.
+ *
+ * @param origin origin where cookie is received from or being sent to.
+ * @return
+ */
+ private static CookieOrigin adjustEffectiveHost(final CookieOrigin origin) {
+ String host = origin.getHost();
+
+ // Test if the host name appears to be a fully qualified DNS name,
+ // IPv4 address or IPv6 address
+ boolean isLocalHost = true;
+ for (int i = 0; i < host.length(); i++) {
+ char ch = host.charAt(i);
+ if (ch == '.' || ch == ':') {
+ isLocalHost = false;
+ break;
+ }
+ }
+ if (isLocalHost) {
+ host += ".local";
+ return new CookieOrigin(
+ host,
+ origin.getPort(),
+ origin.getPath(),
+ origin.isSecure());
+ } else {
+ return origin;
+ }
+ }
+
+ @Override
+ public int getVersion() {
+ return 1;
+ }
+
+ @Override
+ public Header getVersionHeader() {
+ CharArrayBuffer buffer = new CharArrayBuffer(40);
+ buffer.append(SM.COOKIE2);
+ buffer.append(": ");
+ buffer.append("$Version=");
+ buffer.append(Integer.toString(getVersion()));
+ return new BufferedHeader(buffer);
+ }
+
+}
+
diff --git a/src/org/apache/http/impl/cookie/RFC2965SpecFactory.java b/src/org/apache/http/impl/cookie/RFC2965SpecFactory.java
new file mode 100644
index 0000000..4b3cc4d
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965SpecFactory.java
@@ -0,0 +1,57 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java $
+ * $Revision: 581953 $
+ * $Date: 2007-10-04 08:53:50 -0700 (Thu, 04 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecFactory;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class RFC2965SpecFactory implements CookieSpecFactory {
+
+ public CookieSpec newInstance(final HttpParams params) {
+ if (params != null) {
+ return new RFC2965Spec(
+ (String []) params.getParameter(CookieSpecPNames.DATE_PATTERNS),
+ params.getBooleanParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, false));
+ } else {
+ return new RFC2965Spec();
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java b/src/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
new file mode 100644
index 0000000..8ea8481
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
@@ -0,0 +1,96 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java $
+ * $Revision: 590695 $
+ * $Date: 2007-10-31 07:55:41 -0700 (Wed, 31 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.cookie.SetCookie2;
+
+/**
+ * <tt>"Version"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ */
+public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
+
+ public RFC2965VersionAttributeHandler() {
+ super();
+ }
+
+ /**
+ * Parse cookie version attribute.
+ */
+ public void parse(final SetCookie cookie, final String value)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (value == null) {
+ throw new MalformedCookieException(
+ "Missing value for version attribute");
+ }
+ int version = -1;
+ try {
+ version = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ version = -1;
+ }
+ if (version < 0) {
+ throw new MalformedCookieException("Invalid cookie version.");
+ }
+ cookie.setVersion(version);
+ }
+
+ /**
+ * validate cookie version attribute. Version attribute is REQUIRED.
+ */
+ public void validate(final Cookie cookie, final CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (cookie instanceof SetCookie2) {
+ if (cookie instanceof ClientCookie
+ && !((ClientCookie) cookie).containsAttribute(ClientCookie.VERSION_ATTR)) {
+ throw new MalformedCookieException(
+ "Violates RFC 2965. Version attribute is required.");
+ }
+ }
+ }
+
+ public boolean match(final Cookie cookie, final CookieOrigin origin) {
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/org/apache/http/impl/cookie/package.html b/src/org/apache/http/impl/cookie/package.html
new file mode 100644
index 0000000..e301283
--- /dev/null
+++ b/src/org/apache/http/impl/cookie/package.html
@@ -0,0 +1,4 @@
+<body>
+
+</body>
+
diff --git a/src/org/apache/http/impl/entity/EntityDeserializer.java b/src/org/apache/http/impl/entity/EntityDeserializer.java
new file mode 100644
index 0000000..12c4756
--- /dev/null
+++ b/src/org/apache/http/impl/entity/EntityDeserializer.java
@@ -0,0 +1,115 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/entity/EntityDeserializer.java $
+ * $Revision: 560358 $
+ * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.entity;
+
+import java.io.IOException;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.entity.BasicHttpEntity;
+import org.apache.http.entity.ContentLengthStrategy;
+import org.apache.http.impl.io.ChunkedInputStream;
+import org.apache.http.impl.io.ContentLengthInputStream;
+import org.apache.http.impl.io.IdentityInputStream;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Default implementation of an entity deserializer.
+ * <p>
+ * This entity deserializer currently supports only "chunked" and "identitiy" transfer-coding</a>
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560358 $
+ *
+ * @since 4.0
+ */
+public class EntityDeserializer {
+
+ private final ContentLengthStrategy lenStrategy;
+
+ public EntityDeserializer(final ContentLengthStrategy lenStrategy) {
+ super();
+ if (lenStrategy == null) {
+ throw new IllegalArgumentException("Content length strategy may not be null");
+ }
+ this.lenStrategy = lenStrategy;
+ }
+
+ protected BasicHttpEntity doDeserialize(
+ final SessionInputBuffer inbuffer,
+ final HttpMessage message) throws HttpException, IOException {
+ BasicHttpEntity entity = new BasicHttpEntity();
+
+ long len = this.lenStrategy.determineLength(message);
+ if (len == ContentLengthStrategy.CHUNKED) {
+ entity.setChunked(true);
+ entity.setContentLength(-1);
+ entity.setContent(new ChunkedInputStream(inbuffer));
+ } else if (len == ContentLengthStrategy.IDENTITY) {
+ entity.setChunked(false);
+ entity.setContentLength(-1);
+ entity.setContent(new IdentityInputStream(inbuffer));
+ } else {
+ entity.setChunked(false);
+ entity.setContentLength(len);
+ entity.setContent(new ContentLengthInputStream(inbuffer, len));
+ }
+
+ Header contentTypeHeader = message.getFirstHeader(HTTP.CONTENT_TYPE);
+ if (contentTypeHeader != null) {
+ entity.setContentType(contentTypeHeader);
+ }
+ Header contentEncodingHeader = message.getFirstHeader(HTTP.CONTENT_ENCODING);
+ if (contentEncodingHeader != null) {
+ entity.setContentEncoding(contentEncodingHeader);
+ }
+ return entity;
+ }
+
+ public HttpEntity deserialize(
+ final SessionInputBuffer inbuffer,
+ final HttpMessage message) throws HttpException, IOException {
+ if (inbuffer == null) {
+ throw new IllegalArgumentException("Session input buffer may not be null");
+ }
+ if (message == null) {
+ throw new IllegalArgumentException("HTTP message may not be null");
+ }
+ return doDeserialize(inbuffer, message);
+ }
+
+}
diff --git a/src/org/apache/http/impl/entity/EntitySerializer.java b/src/org/apache/http/impl/entity/EntitySerializer.java
new file mode 100644
index 0000000..3221980
--- /dev/null
+++ b/src/org/apache/http/impl/entity/EntitySerializer.java
@@ -0,0 +1,101 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/entity/EntitySerializer.java $
+ * $Revision: 560343 $
+ * $Date: 2007-07-27 11:18:19 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.entity;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.entity.ContentLengthStrategy;
+import org.apache.http.impl.io.ChunkedOutputStream;
+import org.apache.http.impl.io.ContentLengthOutputStream;
+import org.apache.http.impl.io.IdentityOutputStream;
+import org.apache.http.io.SessionOutputBuffer;
+
+/**
+ * Default implementation of an entity serializer.
+ * <p>
+ * This entity serializer currently supports only "chunked" and "identitiy" transfer-coding</a>
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560343 $
+ *
+ * @since 4.0
+ */
+public class EntitySerializer {
+
+ private final ContentLengthStrategy lenStrategy;
+
+ public EntitySerializer(final ContentLengthStrategy lenStrategy) {
+ super();
+ if (lenStrategy == null) {
+ throw new IllegalArgumentException("Content length strategy may not be null");
+ }
+ this.lenStrategy = lenStrategy;
+ }
+
+ protected OutputStream doSerialize(
+ final SessionOutputBuffer outbuffer,
+ final HttpMessage message) throws HttpException, IOException {
+ long len = this.lenStrategy.determineLength(message);
+ if (len == ContentLengthStrategy.CHUNKED) {
+ return new ChunkedOutputStream(outbuffer);
+ } else if (len == ContentLengthStrategy.IDENTITY) {
+ return new IdentityOutputStream(outbuffer);
+ } else {
+ return new ContentLengthOutputStream(outbuffer, len);
+ }
+ }
+
+ public void serialize(
+ final SessionOutputBuffer outbuffer,
+ final HttpMessage message,
+ final HttpEntity entity) throws HttpException, IOException {
+ if (outbuffer == null) {
+ throw new IllegalArgumentException("Session output buffer may not be null");
+ }
+ if (message == null) {
+ throw new IllegalArgumentException("HTTP message may not be null");
+ }
+ if (entity == null) {
+ throw new IllegalArgumentException("HTTP entity may not be null");
+ }
+ OutputStream outstream = doSerialize(outbuffer, message);
+ entity.writeTo(outstream);
+ outstream.close();
+ }
+
+}
diff --git a/src/org/apache/http/impl/entity/LaxContentLengthStrategy.java b/src/org/apache/http/impl/entity/LaxContentLengthStrategy.java
new file mode 100644
index 0000000..9a0d238
--- /dev/null
+++ b/src/org/apache/http/impl/entity/LaxContentLengthStrategy.java
@@ -0,0 +1,260 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/entity/LaxContentLengthStrategy.java $
+ * $Revision: 576073 $
+ * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.entity;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.ParseException;
+import org.apache.http.ProtocolException;
+import org.apache.http.entity.ContentLengthStrategy;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * The lax implementation of the content length strategy.
+ * <p>
+ * This strategy conforms to the entity transfer rules outlined in
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec4.4">Section 4.4</a>,
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>,
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41">Section 14.41</a>
+ * and <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec14.13">Section 14.13</a>
+ * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>, but is lenient
+ * about unsupported transfer codecs and malformed content-length headers.
+ * </p>
+ * <h>4.4 Message Length</h>
+ * <p>
+ * The transfer-length of a message is the length of the message-body as it appears in the
+ * message; that is, after any transfer-codings have been applied. When a message-body is
+ * included with a message, the transfer-length of that body is determined by one of the
+ * following (in order of precedence):
+ * </p>
+ * <p>
+ * 1.Any response message which "MUST NOT" include a message-body (such as the 1xx, 204,
+ * and 304 responses and any response to a HEAD request) is always terminated by the first
+ * empty line after the header fields, regardless of the entity-header fields present in the
+ * message.
+ * </p>
+ * <p>
+ * 2.If a Transfer-Encoding header field (section 14.41) is present and has any value other
+ * than "identity", then the transfer-length is defined by use of the "chunked" transfer-
+ * coding (section 3.6), unless the message is terminated by closing the connection.
+ * </p>
+ * <p>
+ * 3.If a Content-Length header field (section 14.13) is present, its decimal value in
+ * OCTETs represents both the entity-length and the transfer-length. The Content-Length
+ * header field MUST NOT be sent if these two lengths are different (i.e., if a
+ * Transfer-Encoding
+ * </p>
+ * <pre>
+ * header field is present). If a message is received with both a
+ * Transfer-Encoding header field and a Content-Length header field,
+ * the latter MUST be ignored.
+ * </pre>
+ * <p>
+ * 4.If the message uses the media type "multipart/byteranges", and the ransfer-length is not
+ * otherwise specified, then this self- elimiting media type defines the transfer-length.
+ * This media type UST NOT be used unless the sender knows that the recipient can arse it; the
+ * presence in a request of a Range header with ultiple byte- range specifiers from a 1.1
+ * client implies that the lient can parse multipart/byteranges responses.
+ * </p>
+ * <pre>
+ * A range header might be forwarded by a 1.0 proxy that does not
+ * understand multipart/byteranges; in this case the server MUST
+ * delimit the message using methods defined in items 1,3 or 5 of
+ * this section.
+ * </pre>
+ * <p>
+ * 5.By the server closing the connection. (Closing the connection cannot be used to indicate
+ * the end of a request body, since that would leave no possibility for the server to send back
+ * a response.)
+ * </p>
+ * <p>
+ * For compatibility with HTTP/1.0 applications, HTTP/1.1 requests containing a message-body
+ * MUST include a valid Content-Length header field unless the server is known to be HTTP/1.1
+ * compliant. If a request contains a message-body and a Content-Length is not given, the
+ * server SHOULD respond with 400 (bad request) if it cannot determine the length of the
+ * message, or with 411 (length required) if it wishes to insist on receiving a valid
+ * Content-Length.
+ * </p>
+ * <p>All HTTP/1.1 applications that receive entities MUST accept the "chunked" transfer-coding
+ * (section 3.6), thus allowing this mechanism to be used for messages when the message
+ * length cannot be determined in advance.
+ * </p>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Transfer-coding values are used to indicate an encoding transformation that
+ * has been, can be, or may need to be applied to an entity-body in order to ensure
+ * "safe transport" through the network. This differs from a content coding in that
+ * the transfer-coding is a property of the message, not of the original entity.
+ * </p>
+ * <pre>
+ * transfer-coding = "chunked" | transfer-extension
+ * transfer-extension = token *( ";" parameter )
+ * </pre>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ * <p>
+ * All transfer-coding values are case-insensitive. HTTP/1.1 uses transfer-coding values in
+ * the TE header field (section 14.39) and in the Transfer-Encoding header field (section 14.41).
+ * </p>
+ * <p>
+ * Whenever a transfer-coding is applied to a message-body, the set of transfer-codings MUST
+ * include "chunked", unless the message is terminated by closing the connection. When the
+ * "chunked" transfer-coding is used, it MUST be the last transfer-coding applied to the
+ * message-body. The "chunked" transfer-coding MUST NOT be applied more than once to a
+ * message-body. These rules allow the recipient to determine the transfer-length of the
+ * message (section 4.4).
+ * </p>
+ * <h>14.41 Transfer-Encoding</h>
+ * <p>
+ * The Transfer-Encoding general-header field indicates what (if any) type of transformation has
+ * been applied to the message body in order to safely transfer it between the sender and the
+ * recipient. This differs from the content-coding in that the transfer-coding is a property of
+ * the message, not of the entity.
+ * </p>
+ * <pre>
+ * Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
+ * </pre>
+ * <p>
+ * If multiple encodings have been applied to an entity, the transfer- codings MUST be listed in
+ * the order in which they were applied. Additional information about the encoding parameters
+ * MAY be provided by other entity-header fields not defined by this specification.
+ * </p>
+ * <h>14.13 Content-Length</h>
+ * <p>
+ * The Content-Length entity-header field indicates the size of the entity-body, in decimal
+ * number of OCTETs, sent to the recipient or, in the case of the HEAD method, the size of
+ * the entity-body that would have been sent had the request been a GET.
+ * </p>
+ * <pre>
+ * Content-Length = "Content-Length" ":" 1*DIGIT
+ * </pre>
+ * <p>
+ * Applications SHOULD use this field to indicate the transfer-length of the message-body,
+ * unless this is prohibited by the rules in section 4.4.
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 576073 $
+ *
+ * @since 4.0
+ */
+public class LaxContentLengthStrategy implements ContentLengthStrategy {
+
+ public LaxContentLengthStrategy() {
+ super();
+ }
+
+ public long determineLength(final HttpMessage message) throws HttpException {
+ if (message == null) {
+ throw new IllegalArgumentException("HTTP message may not be null");
+ }
+
+ HttpParams params = message.getParams();
+ boolean strict = params.isParameterTrue(CoreProtocolPNames.STRICT_TRANSFER_ENCODING);
+
+ Header transferEncodingHeader = message.getFirstHeader(HTTP.TRANSFER_ENCODING);
+ Header contentLengthHeader = message.getFirstHeader(HTTP.CONTENT_LEN);
+ // We use Transfer-Encoding if present and ignore Content-Length.
+ // RFC2616, 4.4 item number 3
+ if (transferEncodingHeader != null) {
+ HeaderElement[] encodings = null;
+ try {
+ encodings = transferEncodingHeader.getElements();
+ } catch (ParseException px) {
+ throw new ProtocolException
+ ("Invalid Transfer-Encoding header value: " +
+ transferEncodingHeader, px);
+ }
+ if (strict) {
+ // Currently only chunk and identity are supported
+ for (int i = 0; i < encodings.length; i++) {
+ String encoding = encodings[i].getName();
+ if (encoding != null && encoding.length() > 0
+ && !encoding.equalsIgnoreCase(HTTP.CHUNK_CODING)
+ && !encoding.equalsIgnoreCase(HTTP.IDENTITY_CODING)) {
+ throw new ProtocolException("Unsupported transfer encoding: " + encoding);
+ }
+ }
+ }
+ // The chunked encoding must be the last one applied RFC2616, 14.41
+ int len = encodings.length;
+ if (HTTP.IDENTITY_CODING.equalsIgnoreCase(transferEncodingHeader.getValue())) {
+ return IDENTITY;
+ } else if ((len > 0) && (HTTP.CHUNK_CODING.equalsIgnoreCase(
+ encodings[len - 1].getName()))) {
+ return CHUNKED;
+ } else {
+ if (strict) {
+ throw new ProtocolException("Chunk-encoding must be the last one applied");
+ }
+ return IDENTITY;
+ }
+ } else if (contentLengthHeader != null) {
+ long contentlen = -1;
+ Header[] headers = message.getHeaders(HTTP.CONTENT_LEN);
+ if (strict && headers.length > 1) {
+ throw new ProtocolException("Multiple content length headers");
+ }
+ for (int i = headers.length - 1; i >= 0; i--) {
+ Header header = headers[i];
+ try {
+ contentlen = Long.parseLong(header.getValue());
+ break;
+ } catch (NumberFormatException e) {
+ if (strict) {
+ throw new ProtocolException("Invalid content length: " + header.getValue());
+ }
+ }
+ // See if we can have better luck with another header, if present
+ }
+ if (contentlen >= 0) {
+ return contentlen;
+ } else {
+ return IDENTITY;
+ }
+ } else {
+ return IDENTITY;
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/entity/StrictContentLengthStrategy.java b/src/org/apache/http/impl/entity/StrictContentLengthStrategy.java
new file mode 100644
index 0000000..30be8e2
--- /dev/null
+++ b/src/org/apache/http/impl/entity/StrictContentLengthStrategy.java
@@ -0,0 +1,220 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/entity/StrictContentLengthStrategy.java $
+ * $Revision: 573949 $
+ * $Date: 2007-09-08 22:46:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.entity;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolException;
+import org.apache.http.entity.ContentLengthStrategy;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * The strict implementation of the content length strategy.
+ * <p>
+ * This entity generator comforms to the entity transfer rules outlined in the
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec4.4">Section 4.4</a>,
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>,
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41">Section 14.41</a>
+ * and <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec14.13">Section 14.13</a>
+ * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
+ * </p>
+ * <h>4.4 Message Length</h>
+ * <p>
+ * The transfer-length of a message is the length of the message-body as it appears in the
+ * message; that is, after any transfer-codings have been applied. When a message-body is
+ * included with a message, the transfer-length of that body is determined by one of the
+ * following (in order of precedence):
+ * </p>
+ * <p>
+ * 1.Any response message which "MUST NOT" include a message-body (such as the 1xx, 204,
+ * and 304 responses and any response to a HEAD request) is always terminated by the first
+ * empty line after the header fields, regardless of the entity-header fields present in the
+ * message.
+ * </p>
+ * <p>
+ * 2.If a Transfer-Encoding header field (section 14.41) is present and has any value other
+ * than "identity", then the transfer-length is defined by use of the "chunked" transfer-
+ * coding (section 3.6), unless the message is terminated by closing the connection.
+ * </p>
+ * <p>
+ * 3.If a Content-Length header field (section 14.13) is present, its decimal value in
+ * OCTETs represents both the entity-length and the transfer-length. The Content-Length
+ * header field MUST NOT be sent if these two lengths are different (i.e., if a
+ * Transfer-Encoding
+ * </p>
+ * <pre>
+ * header field is present). If a message is received with both a
+ * Transfer-Encoding header field and a Content-Length header field,
+ * the latter MUST be ignored.
+ * </pre>
+ * <p>
+ * 4.If the message uses the media type "multipart/byteranges", and the ransfer-length is not
+ * otherwise specified, then this self- elimiting media type defines the transfer-length.
+ * This media type UST NOT be used unless the sender knows that the recipient can arse it; the
+ * presence in a request of a Range header with ultiple byte- range specifiers from a 1.1
+ * client implies that the lient can parse multipart/byteranges responses.
+ * </p>
+ * <pre>
+ * A range header might be forwarded by a 1.0 proxy that does not
+ * understand multipart/byteranges; in this case the server MUST
+ * delimit the message using methods defined in items 1,3 or 5 of
+ * this section.
+ * </pre>
+ * <p>
+ * 5.By the server closing the connection. (Closing the connection cannot be used to indicate
+ * the end of a request body, since that would leave no possibility for the server to send back
+ * a response.)
+ * </p>
+ * <p>
+ * For compatibility with HTTP/1.0 applications, HTTP/1.1 requests containing a message-body
+ * MUST include a valid Content-Length header field unless the server is known to be HTTP/1.1
+ * compliant. If a request contains a message-body and a Content-Length is not given, the
+ * server SHOULD respond with 400 (bad request) if it cannot determine the length of the
+ * message, or with 411 (length required) if it wishes to insist on receiving a valid
+ * Content-Length.
+ * </p>
+ * <p>All HTTP/1.1 applications that receive entities MUST accept the "chunked" transfer-coding
+ * (section 3.6), thus allowing this mechanism to be used for messages when the message
+ * length cannot be determined in advance.
+ * </p>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Transfer-coding values are used to indicate an encoding transformation that
+ * has been, can be, or may need to be applied to an entity-body in order to ensure
+ * "safe transport" through the network. This differs from a content coding in that
+ * the transfer-coding is a property of the message, not of the original entity.
+ * </p>
+ * <pre>
+ * transfer-coding = "chunked" | transfer-extension
+ * transfer-extension = token *( ";" parameter )
+ * </pre>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ * <p>
+ * All transfer-coding values are case-insensitive. HTTP/1.1 uses transfer-coding values in
+ * the TE header field (section 14.39) and in the Transfer-Encoding header field (section 14.41).
+ * </p>
+ * <p>
+ * Whenever a transfer-coding is applied to a message-body, the set of transfer-codings MUST
+ * include "chunked", unless the message is terminated by closing the connection. When the
+ * "chunked" transfer-coding is used, it MUST be the last transfer-coding applied to the
+ * message-body. The "chunked" transfer-coding MUST NOT be applied more than once to a
+ * message-body. These rules allow the recipient to determine the transfer-length of the
+ * message (section 4.4).
+ * </p>
+ * <h>14.41 Transfer-Encoding</h>
+ * <p>
+ * The Transfer-Encoding general-header field indicates what (if any) type of transformation has
+ * been applied to the message body in order to safely transfer it between the sender and the
+ * recipient. This differs from the content-coding in that the transfer-coding is a property of
+ * the message, not of the entity.
+ * </p>
+ * <pre>
+ * Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
+ * </pre>
+ * <p>
+ * If multiple encodings have been applied to an entity, the transfer- codings MUST be listed in
+ * the order in which they were applied. Additional information about the encoding parameters
+ * MAY be provided by other entity-header fields not defined by this specification.
+ * </p>
+ * <h>14.13 Content-Length</h>
+ * <p>
+ * The Content-Length entity-header field indicates the size of the entity-body, in decimal
+ * number of OCTETs, sent to the recipient or, in the case of the HEAD method, the size of
+ * the entity-body that would have been sent had the request been a GET.
+ * </p>
+ * <pre>
+ * Content-Length = "Content-Length" ":" 1*DIGIT
+ * </pre>
+ * <p>
+ * Applications SHOULD use this field to indicate the transfer-length of the message-body,
+ * unless this is prohibited by the rules in section 4.4.
+ * </p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573949 $
+ *
+ * @since 4.0
+ */
+public class StrictContentLengthStrategy implements ContentLengthStrategy {
+
+ public StrictContentLengthStrategy() {
+ super();
+ }
+
+ public long determineLength(final HttpMessage message) throws HttpException {
+ if (message == null) {
+ throw new IllegalArgumentException("HTTP message may not be null");
+ }
+ // Although Transfer-Encoding is specified as a list, in practice
+ // it is either missing or has the single value "chunked". So we
+ // treat it as a single-valued header here.
+ Header transferEncodingHeader = message.getFirstHeader(HTTP.TRANSFER_ENCODING);
+ Header contentLengthHeader = message.getFirstHeader(HTTP.CONTENT_LEN);
+ if (transferEncodingHeader != null) {
+ String s = transferEncodingHeader.getValue();
+ if (HTTP.CHUNK_CODING.equalsIgnoreCase(s)) {
+ if (message.getProtocolVersion().lessEquals(HttpVersion.HTTP_1_0)) {
+ throw new ProtocolException(
+ "Chunked transfer encoding not allowed for " +
+ message.getProtocolVersion());
+ }
+ return CHUNKED;
+ } else if (HTTP.IDENTITY_CODING.equalsIgnoreCase(s)) {
+ return IDENTITY;
+ } else {
+ throw new ProtocolException(
+ "Unsupported transfer encoding: " + s);
+ }
+ } else if (contentLengthHeader != null) {
+ String s = contentLengthHeader.getValue();
+ try {
+ long len = Long.parseLong(s);
+ return len;
+ } catch (NumberFormatException e) {
+ throw new ProtocolException("Invalid content length: " + s);
+ }
+ } else {
+ return IDENTITY;
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/entity/package.html b/src/org/apache/http/impl/entity/package.html
new file mode 100644
index 0000000..9ac4481
--- /dev/null
+++ b/src/org/apache/http/impl/entity/package.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/entity/package.html $
+ * $Revision: 496072 $
+ * $Date: 2007-01-14 04:22:55 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Default implementations for interfaces in
+{@link org.apache.http.entity org.apache.http.entity}.
+
+</body>
+</html>
diff --git a/src/org/apache/http/impl/io/AbstractMessageParser.java b/src/org/apache/http/impl/io/AbstractMessageParser.java
new file mode 100644
index 0000000..679bcd1
--- /dev/null
+++ b/src/org/apache/http/impl/io/AbstractMessageParser.java
@@ -0,0 +1,187 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.ParseException;
+import org.apache.http.ProtocolException;
+import org.apache.http.io.HttpMessageParser;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.message.LineParser;
+import org.apache.http.message.BasicLineParser;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Message parser base class.
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public abstract class AbstractMessageParser implements HttpMessageParser {
+
+ private final SessionInputBuffer sessionBuffer;
+ private final int maxHeaderCount;
+ private final int maxLineLen;
+ protected final LineParser lineParser;
+
+
+ public AbstractMessageParser(
+ final SessionInputBuffer buffer,
+ final LineParser parser,
+ final HttpParams params) {
+ super();
+ if (buffer == null) {
+ throw new IllegalArgumentException("Session input buffer may not be null");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.sessionBuffer = buffer;
+ this.maxHeaderCount = params.getIntParameter(
+ CoreConnectionPNames.MAX_HEADER_COUNT, -1);
+ this.maxLineLen = params.getIntParameter(
+ CoreConnectionPNames.MAX_LINE_LENGTH, -1);
+ this.lineParser = (parser != null) ? parser : BasicLineParser.DEFAULT;
+ }
+
+ /**
+ * Parses HTTP headers from the data receiver stream according to the generic
+ * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3.
+ *
+ * @param inbuffer Session input buffer
+ * @param maxHeaderCount maximum number of headers allowed. If the number
+ * of headers received from the data stream exceeds maxCount value, an
+ * IOException will be thrown. Setting this parameter to a negative value
+ * or zero will disable the check.
+ * @param maxLineLen maximum number of characters for a header line,
+ * including the continuation lines
+ * @return array of HTTP headers
+ *
+ * @throws HttpException
+ * @throws IOException
+ */
+ public static Header[] parseHeaders(
+ final SessionInputBuffer inbuffer,
+ int maxHeaderCount,
+ int maxLineLen,
+ LineParser parser)
+ throws HttpException, IOException {
+
+ if (inbuffer == null) {
+ throw new IllegalArgumentException("Session input buffer may not be null");
+ }
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ ArrayList headerLines = new ArrayList();
+
+ CharArrayBuffer current = null;
+ CharArrayBuffer previous = null;
+ for (;;) {
+ if (current == null) {
+ current = new CharArrayBuffer(64);
+ } else {
+ current.clear();
+ }
+ int l = inbuffer.readLine(current);
+ if (l == -1 || current.length() < 1) {
+ break;
+ }
+ // Parse the header name and value
+ // Check for folded headers first
+ // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
+ // discussion on folded headers
+ if ((current.charAt(0) == ' ' || current.charAt(0) == '\t') && previous != null) {
+ // we have continuation folded header
+ // so append value
+ int i = 0;
+ while (i < current.length()) {
+ char ch = current.charAt(i);
+ if (ch != ' ' && ch != '\t') {
+ break;
+ }
+ i++;
+ }
+ if (maxLineLen > 0
+ && previous.length() + 1 + current.length() - i > maxLineLen) {
+ throw new IOException("Maximum line length limit exceeded");
+ }
+ previous.append(' ');
+ previous.append(current, i, current.length() - i);
+ } else {
+ headerLines.add(current);
+ previous = current;
+ current = null;
+ }
+ if (maxHeaderCount > 0 && headerLines.size() >= maxHeaderCount) {
+ throw new IOException("Maximum header count exceeded");
+ }
+ }
+ Header[] headers = new Header[headerLines.size()];
+ for (int i = 0; i < headerLines.size(); i++) {
+ CharArrayBuffer buffer = (CharArrayBuffer) headerLines.get(i);
+ try {
+ headers[i] = parser.parseHeader(buffer);
+ } catch (ParseException ex) {
+ throw new ProtocolException(ex.getMessage());
+ }
+ }
+ return headers;
+ }
+
+ protected abstract HttpMessage parseHead(SessionInputBuffer sessionBuffer)
+ throws IOException, HttpException, ParseException;
+
+ public HttpMessage parse() throws IOException, HttpException {
+ HttpMessage message = null;
+ try {
+ message = parseHead(this.sessionBuffer);
+ } catch (ParseException px) {
+ throw new ProtocolException(px.getMessage(), px);
+ }
+ Header[] headers = AbstractMessageParser.parseHeaders(
+ this.sessionBuffer,
+ this.maxHeaderCount,
+ this.maxLineLen,
+ this.lineParser);
+ message.setHeaders(headers);
+ return message;
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/AbstractMessageWriter.java b/src/org/apache/http/impl/io/AbstractMessageWriter.java
new file mode 100644
index 0000000..f9644ce
--- /dev/null
+++ b/src/org/apache/http/impl/io/AbstractMessageWriter.java
@@ -0,0 +1,85 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractMessageWriter.java $
+ * $Revision: 569673 $
+ * $Date: 2007-08-25 06:58:51 -0700 (Sat, 25 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.io.HttpMessageWriter;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.message.LineFormatter;
+import org.apache.http.message.BasicLineFormatter;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+public abstract class AbstractMessageWriter implements HttpMessageWriter {
+
+ protected final SessionOutputBuffer sessionBuffer;
+ protected final CharArrayBuffer lineBuf;
+ protected final LineFormatter lineFormatter;
+
+ public AbstractMessageWriter(final SessionOutputBuffer buffer,
+ final LineFormatter formatter,
+ final HttpParams params) {
+ super();
+ if (buffer == null) {
+ throw new IllegalArgumentException("Session input buffer may not be null");
+ }
+ this.sessionBuffer = buffer;
+ this.lineBuf = new CharArrayBuffer(128);
+ this.lineFormatter = (formatter != null) ?
+ formatter : BasicLineFormatter.DEFAULT;
+ }
+
+ protected abstract void writeHeadLine(HttpMessage message)
+ throws IOException
+ ;
+
+ public void write(
+ final HttpMessage message) throws IOException, HttpException {
+ if (message == null) {
+ throw new IllegalArgumentException("HTTP message may not be null");
+ }
+ writeHeadLine(message);
+ for (Iterator it = message.headerIterator(); it.hasNext(); ) {
+ Header header = (Header) it.next();
+ this.sessionBuffer.writeLine
+ (lineFormatter.formatHeader(this.lineBuf, header));
+ }
+ this.lineBuf.clear();
+ this.sessionBuffer.writeLine(this.lineBuf);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/AbstractSessionInputBuffer.java b/src/org/apache/http/impl/io/AbstractSessionInputBuffer.java
new file mode 100644
index 0000000..eb007a9
--- /dev/null
+++ b/src/org/apache/http/impl/io/AbstractSessionInputBuffer.java
@@ -0,0 +1,271 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.io.HttpTransportMetrics;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.ByteArrayBuffer;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Abstract base class for session input buffers that stream data
+ * from a {@link InputStream}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ */
+public abstract class AbstractSessionInputBuffer implements SessionInputBuffer {
+
+ private InputStream instream;
+ private byte[] buffer;
+ private int bufferpos;
+ private int bufferlen;
+
+ private ByteArrayBuffer linebuffer = null;
+
+ private String charset = HTTP.US_ASCII;
+ private boolean ascii = true;
+ private int maxLineLen = -1;
+
+ private HttpTransportMetricsImpl metrics;
+
+ protected void init(final InputStream instream, int buffersize, final HttpParams params) {
+ if (instream == null) {
+ throw new IllegalArgumentException("Input stream may not be null");
+ }
+ if (buffersize <= 0) {
+ throw new IllegalArgumentException("Buffer size may not be negative or zero");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.instream = instream;
+ this.buffer = new byte[buffersize];
+ this.bufferpos = 0;
+ this.bufferlen = 0;
+ this.linebuffer = new ByteArrayBuffer(buffersize);
+ this.charset = HttpProtocolParams.getHttpElementCharset(params);
+ this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII)
+ || this.charset.equalsIgnoreCase(HTTP.ASCII);
+ this.maxLineLen = params.getIntParameter(CoreConnectionPNames.MAX_LINE_LENGTH, -1);
+ this.metrics = new HttpTransportMetricsImpl();
+ }
+
+ protected int fillBuffer() throws IOException {
+ // compact the buffer if necessary
+ if (this.bufferpos > 0) {
+ int len = this.bufferlen - this.bufferpos;
+ if (len > 0) {
+ System.arraycopy(this.buffer, this.bufferpos, this.buffer, 0, len);
+ }
+ this.bufferpos = 0;
+ this.bufferlen = len;
+ }
+ int l;
+ int off = this.bufferlen;
+ int len = this.buffer.length - off;
+ l = this.instream.read(this.buffer, off, len);
+ if (l == -1) {
+ return -1;
+ } else {
+ this.bufferlen = off + l;
+ this.metrics.incrementBytesTransferred(l);
+ return l;
+ }
+ }
+
+ protected boolean hasBufferedData() {
+ return this.bufferpos < this.bufferlen;
+ }
+
+ public int read() throws IOException {
+ int noRead = 0;
+ while (!hasBufferedData()) {
+ noRead = fillBuffer();
+ if (noRead == -1) {
+ return -1;
+ }
+ }
+ return this.buffer[this.bufferpos++] & 0xff;
+ }
+
+ public int read(final byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ return 0;
+ }
+ int noRead = 0;
+ while (!hasBufferedData()) {
+ noRead = fillBuffer();
+ if (noRead == -1) {
+ return -1;
+ }
+ }
+ int chunk = this.bufferlen - this.bufferpos;
+ if (chunk > len) {
+ chunk = len;
+ }
+ System.arraycopy(this.buffer, this.bufferpos, b, off, chunk);
+ this.bufferpos += chunk;
+ return chunk;
+ }
+
+ public int read(final byte[] b) throws IOException {
+ if (b == null) {
+ return 0;
+ }
+ return read(b, 0, b.length);
+ }
+
+ private int locateLF() {
+ for (int i = this.bufferpos; i < this.bufferlen; i++) {
+ if (this.buffer[i] == HTTP.LF) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int readLine(final CharArrayBuffer charbuffer) throws IOException {
+ if (charbuffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ this.linebuffer.clear();
+ int noRead = 0;
+ boolean retry = true;
+ while (retry) {
+ // attempt to find end of line (LF)
+ int i = locateLF();
+ if (i != -1) {
+ // end of line found.
+ if (this.linebuffer.isEmpty()) {
+ // the entire line is preset in the read buffer
+ return lineFromReadBuffer(charbuffer, i);
+ }
+ retry = false;
+ int len = i + 1 - this.bufferpos;
+ this.linebuffer.append(this.buffer, this.bufferpos, len);
+ this.bufferpos = i + 1;
+ } else {
+ // end of line not found
+ if (hasBufferedData()) {
+ int len = this.bufferlen - this.bufferpos;
+ this.linebuffer.append(this.buffer, this.bufferpos, len);
+ this.bufferpos = this.bufferlen;
+ }
+ noRead = fillBuffer();
+ if (noRead == -1) {
+ retry = false;
+ }
+ }
+ if (this.maxLineLen > 0 && this.linebuffer.length() >= this.maxLineLen) {
+ throw new IOException("Maximum line length limit exceeded");
+ }
+ }
+ if (noRead == -1 && this.linebuffer.isEmpty()) {
+ // indicate the end of stream
+ return -1;
+ }
+ return lineFromLineBuffer(charbuffer);
+ }
+
+ private int lineFromLineBuffer(final CharArrayBuffer charbuffer)
+ throws IOException {
+ // discard LF if found
+ int l = this.linebuffer.length();
+ if (l > 0) {
+ if (this.linebuffer.byteAt(l - 1) == HTTP.LF) {
+ l--;
+ this.linebuffer.setLength(l);
+ }
+ // discard CR if found
+ if (l > 0) {
+ if (this.linebuffer.byteAt(l - 1) == HTTP.CR) {
+ l--;
+ this.linebuffer.setLength(l);
+ }
+ }
+ }
+ l = this.linebuffer.length();
+ if (this.ascii) {
+ charbuffer.append(this.linebuffer, 0, l);
+ } else {
+ // This is VERY memory inefficient, BUT since non-ASCII charsets are
+ // NOT meant to be used anyway, there's no point optimizing it
+ String s = new String(this.linebuffer.buffer(), 0, l, this.charset);
+ charbuffer.append(s);
+ }
+ return l;
+ }
+
+ private int lineFromReadBuffer(final CharArrayBuffer charbuffer, int pos)
+ throws IOException {
+ int off = this.bufferpos;
+ int len;
+ this.bufferpos = pos + 1;
+ if (pos > 0 && this.buffer[pos - 1] == HTTP.CR) {
+ // skip CR if found
+ pos--;
+ }
+ len = pos - off;
+ if (this.ascii) {
+ charbuffer.append(this.buffer, off, len);
+ } else {
+ // This is VERY memory inefficient, BUT since non-ASCII charsets are
+ // NOT meant to be used anyway, there's no point optimizing it
+ String s = new String(this.buffer, off, len, this.charset);
+ charbuffer.append(s);
+ }
+ return len;
+ }
+
+ public String readLine() throws IOException {
+ CharArrayBuffer charbuffer = new CharArrayBuffer(64);
+ int l = readLine(charbuffer);
+ if (l != -1) {
+ return charbuffer.toString();
+ } else {
+ return null;
+ }
+ }
+
+ public HttpTransportMetrics getMetrics() {
+ return this.metrics;
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java b/src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java
new file mode 100644
index 0000000..bf4e56e
--- /dev/null
+++ b/src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java
@@ -0,0 +1,179 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionOutputBuffer.java $
+ * $Revision: 652091 $
+ * $Date: 2008-04-29 13:41:07 -0700 (Tue, 29 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.io.HttpTransportMetrics;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.ByteArrayBuffer;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Abstract base class for session output buffers that stream data
+ * to an {@link OutputStream}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ */
+public abstract class AbstractSessionOutputBuffer implements SessionOutputBuffer {
+
+ private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF};
+
+ private static final int MAX_CHUNK = 256;
+
+ private OutputStream outstream;
+ private ByteArrayBuffer buffer;
+
+ private String charset = HTTP.US_ASCII;
+ private boolean ascii = true;
+
+ private HttpTransportMetricsImpl metrics;
+
+ protected void init(final OutputStream outstream, int buffersize, final HttpParams params) {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Input stream may not be null");
+ }
+ if (buffersize <= 0) {
+ throw new IllegalArgumentException("Buffer size may not be negative or zero");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.outstream = outstream;
+ this.buffer = new ByteArrayBuffer(buffersize);
+ this.charset = HttpProtocolParams.getHttpElementCharset(params);
+ this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII)
+ || this.charset.equalsIgnoreCase(HTTP.ASCII);
+ this.metrics = new HttpTransportMetricsImpl();
+ }
+
+ protected void flushBuffer() throws IOException {
+ int len = this.buffer.length();
+ if (len > 0) {
+ this.outstream.write(this.buffer.buffer(), 0, len);
+ this.buffer.clear();
+ this.metrics.incrementBytesTransferred(len);
+ }
+ }
+
+ public void flush() throws IOException {
+ flushBuffer();
+ this.outstream.flush();
+ }
+
+ public void write(final byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ return;
+ }
+ // Do not want to buffer largish chunks
+ // if the byte array is larger then MAX_CHUNK
+ // write it directly to the output stream
+ if (len > MAX_CHUNK || len > this.buffer.capacity()) {
+ // flush the buffer
+ flushBuffer();
+ // write directly to the out stream
+ this.outstream.write(b, off, len);
+ this.metrics.incrementBytesTransferred(len);
+ } else {
+ // Do not let the buffer grow unnecessarily
+ int freecapacity = this.buffer.capacity() - this.buffer.length();
+ if (len > freecapacity) {
+ // flush the buffer
+ flushBuffer();
+ }
+ // buffer
+ this.buffer.append(b, off, len);
+ }
+ }
+
+ public void write(final byte[] b) throws IOException {
+ if (b == null) {
+ return;
+ }
+ write(b, 0, b.length);
+ }
+
+ public void write(int b) throws IOException {
+ if (this.buffer.isFull()) {
+ flushBuffer();
+ }
+ this.buffer.append(b);
+ }
+
+ public void writeLine(final String s) throws IOException {
+ if (s == null) {
+ return;
+ }
+ if (s.length() > 0) {
+ write(s.getBytes(this.charset));
+ }
+ write(CRLF);
+ }
+
+ public void writeLine(final CharArrayBuffer s) throws IOException {
+ if (s == null) {
+ return;
+ }
+ if (this.ascii) {
+ int off = 0;
+ int remaining = s.length();
+ while (remaining > 0) {
+ int chunk = this.buffer.capacity() - this.buffer.length();
+ chunk = Math.min(chunk, remaining);
+ if (chunk > 0) {
+ this.buffer.append(s, off, chunk);
+ }
+ if (this.buffer.isFull()) {
+ flushBuffer();
+ }
+ off += chunk;
+ remaining -= chunk;
+ }
+ } else {
+ // This is VERY memory inefficient, BUT since non-ASCII charsets are
+ // NOT meant to be used anyway, there's no point optimizing it
+ byte[] tmp = s.toString().getBytes(this.charset);
+ write(tmp);
+ }
+ write(CRLF);
+ }
+
+ public HttpTransportMetrics getMetrics() {
+ return this.metrics;
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/ChunkedInputStream.java b/src/org/apache/http/impl/io/ChunkedInputStream.java
new file mode 100644
index 0000000..60cae90
--- /dev/null
+++ b/src/org/apache/http/impl/io/ChunkedInputStream.java
@@ -0,0 +1,294 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java $
+ * $Revision: 569843 $
+ * $Date: 2007-08-26 10:05:40 -0700 (Sun, 26 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.MalformedChunkCodingException;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.ExceptionUtils;
+
+/**
+ * Implements chunked transfer coding.
+ * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>,
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>.
+ * It transparently coalesces chunks of a HTTP stream that uses chunked
+ * transfer coding. After the stream is read to the end, it provides access
+ * to the trailers, if any.
+ * <p>
+ * Note that this class NEVER closes the underlying stream, even when close
+ * gets called. Instead, it will read until the "end" of its chunking on
+ * close, which allows for the seamless execution of subsequent HTTP 1.1
+ * requests, while not requiring the client to remember to read the entire
+ * contents of the response.
+ * </p>
+ *
+ * @author Ortwin Glueck
+ * @author Sean C. Sullivan
+ * @author Martin Elwin
+ * @author Eric Johnson
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author Michael Becke
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ *
+ */
+public class ChunkedInputStream extends InputStream {
+
+ /** The session input buffer */
+ private SessionInputBuffer in;
+
+ private final CharArrayBuffer buffer;
+
+ /** The chunk size */
+ private int chunkSize;
+
+ /** The current position within the current chunk */
+ private int pos;
+
+ /** True if we'are at the beginning of stream */
+ private boolean bof = true;
+
+ /** True if we've reached the end of stream */
+ private boolean eof = false;
+
+ /** True if this stream is closed */
+ private boolean closed = false;
+
+ private Header[] footers = new Header[] {};
+
+ public ChunkedInputStream(final SessionInputBuffer in) {
+ super();
+ if (in == null) {
+ throw new IllegalArgumentException("Session input buffer may not be null");
+ }
+ this.in = in;
+ this.pos = 0;
+ this.buffer = new CharArrayBuffer(16);
+ }
+
+ /**
+ * <p> Returns all the data in a chunked stream in coalesced form. A chunk
+ * is followed by a CRLF. The method returns -1 as soon as a chunksize of 0
+ * is detected.</p>
+ *
+ * <p> Trailer headers are read automcatically at the end of the stream and
+ * can be obtained with the getResponseFooters() method.</p>
+ *
+ * @return -1 of the end of the stream has been reached or the next data
+ * byte
+ * @throws IOException If an IO problem occurs
+ */
+ public int read() throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted read from closed stream.");
+ }
+ if (this.eof) {
+ return -1;
+ }
+ if (this.pos >= this.chunkSize) {
+ nextChunk();
+ if (this.eof) {
+ return -1;
+ }
+ }
+ pos++;
+ return in.read();
+ }
+
+ /**
+ * Read some bytes from the stream.
+ * @param b The byte array that will hold the contents from the stream.
+ * @param off The offset into the byte array at which bytes will start to be
+ * placed.
+ * @param len the maximum number of bytes that can be returned.
+ * @return The number of bytes returned or -1 if the end of stream has been
+ * reached.
+ * @see java.io.InputStream#read(byte[], int, int)
+ * @throws IOException if an IO problem occurs.
+ */
+ public int read (byte[] b, int off, int len) throws IOException {
+
+ if (closed) {
+ throw new IOException("Attempted read from closed stream.");
+ }
+
+ if (eof) {
+ return -1;
+ }
+ if (pos >= chunkSize) {
+ nextChunk();
+ if (eof) {
+ return -1;
+ }
+ }
+ len = Math.min(len, chunkSize - pos);
+ int count = in.read(b, off, len);
+ pos += count;
+ return count;
+ }
+
+ /**
+ * Read some bytes from the stream.
+ * @param b The byte array that will hold the contents from the stream.
+ * @return The number of bytes returned or -1 if the end of stream has been
+ * reached.
+ * @see java.io.InputStream#read(byte[])
+ * @throws IOException if an IO problem occurs.
+ */
+ public int read (byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Read the next chunk.
+ * @throws IOException If an IO error occurs.
+ */
+ private void nextChunk() throws IOException {
+ chunkSize = getChunkSize();
+ if (chunkSize < 0) {
+ throw new MalformedChunkCodingException("Negative chunk size");
+ }
+ bof = false;
+ pos = 0;
+ if (chunkSize == 0) {
+ eof = true;
+ parseTrailerHeaders();
+ }
+ }
+
+ /**
+ * Expects the stream to start with a chunksize in hex with optional
+ * comments after a semicolon. The line must end with a CRLF: "a3; some
+ * comment\r\n" Positions the stream at the start of the next line.
+ *
+ * @param in The new input stream.
+ * @param required <tt>true<tt/> if a valid chunk must be present,
+ * <tt>false<tt/> otherwise.
+ *
+ * @return the chunk size as integer
+ *
+ * @throws IOException when the chunk size could not be parsed
+ */
+ private int getChunkSize() throws IOException {
+ // skip CRLF
+ if (!bof) {
+ int cr = in.read();
+ int lf = in.read();
+ if ((cr != HTTP.CR) || (lf != HTTP.LF)) {
+ throw new MalformedChunkCodingException(
+ "CRLF expected at end of chunk");
+ }
+ }
+ //parse data
+ this.buffer.clear();
+ int i = this.in.readLine(this.buffer);
+ if (i == -1) {
+ throw new MalformedChunkCodingException(
+ "Chunked stream ended unexpectedly");
+ }
+ int separator = this.buffer.indexOf(';');
+ if (separator < 0) {
+ separator = this.buffer.length();
+ }
+ try {
+ return Integer.parseInt(this.buffer.substringTrimmed(0, separator), 16);
+ } catch (NumberFormatException e) {
+ throw new MalformedChunkCodingException("Bad chunk header");
+ }
+ }
+
+ /**
+ * Reads and stores the Trailer headers.
+ * @throws IOException If an IO problem occurs
+ */
+ private void parseTrailerHeaders() throws IOException {
+ try {
+ this.footers = AbstractMessageParser.parseHeaders
+ (in, -1, -1, null);
+ } catch (HttpException e) {
+ IOException ioe = new MalformedChunkCodingException("Invalid footer: "
+ + e.getMessage());
+ ExceptionUtils.initCause(ioe, e);
+ throw ioe;
+ }
+ }
+
+ /**
+ * Upon close, this reads the remainder of the chunked message,
+ * leaving the underlying socket at a position to start reading the
+ * next response without scanning.
+ * @throws IOException If an IO problem occurs.
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ try {
+ if (!eof) {
+ exhaustInputStream(this);
+ }
+ } finally {
+ eof = true;
+ closed = true;
+ }
+ }
+ }
+
+ public Header[] getFooters() {
+ return (Header[])this.footers.clone();
+ }
+
+ /**
+ * Exhaust an input stream, reading until EOF has been encountered.
+ *
+ * <p>Note that this function is intended as a non-public utility.
+ * This is a little weird, but it seemed silly to make a utility
+ * class for this one function, so instead it is just static and
+ * shared that way.</p>
+ *
+ * @param inStream The {@link InputStream} to exhaust.
+ * @throws IOException If an IO problem occurs
+ */
+ static void exhaustInputStream(final InputStream inStream) throws IOException {
+ // read and discard the remainder of the message
+ byte buffer[] = new byte[1024];
+ while (inStream.read(buffer) >= 0) {
+ ;
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/ChunkedOutputStream.java b/src/org/apache/http/impl/io/ChunkedOutputStream.java
new file mode 100644
index 0000000..5ee7dd6
--- /dev/null
+++ b/src/org/apache/http/impl/io/ChunkedOutputStream.java
@@ -0,0 +1,191 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ChunkedOutputStream.java $
+ * $Revision: 645081 $
+ * $Date: 2008-04-05 04:36:42 -0700 (Sat, 05 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.http.io.SessionOutputBuffer;
+
+/**
+ * Implements chunked transfer coding.
+ * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>,
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>.
+ * Writes are buffered to an internal buffer (2048 default size).
+ *
+ * @author Mohammad Rezaei (Goldman, Sachs &amp; Co.)
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public class ChunkedOutputStream extends OutputStream {
+
+ // ----------------------------------------------------- Instance Variables
+ private final SessionOutputBuffer out;
+
+ private byte[] cache;
+
+ private int cachePosition = 0;
+
+ private boolean wroteLastChunk = false;
+
+ /** True if the stream is closed. */
+ private boolean closed = false;
+
+ // ----------------------------------------------------------- Constructors
+ /**
+ * Wraps a session output buffer and chunks the output.
+ * @param out the session output buffer to wrap
+ * @param bufferSize minimum chunk size (excluding last chunk)
+ * @throws IOException
+ */
+ public ChunkedOutputStream(final SessionOutputBuffer out, int bufferSize)
+ throws IOException {
+ super();
+ this.cache = new byte[bufferSize];
+ this.out = out;
+ }
+
+ /**
+ * Wraps a session output buffer and chunks the output. The default buffer
+ * size of 2048 was chosen because the chunk overhead is less than 0.5%
+ *
+ * @param out the output buffer to wrap
+ * @throws IOException
+ */
+ public ChunkedOutputStream(final SessionOutputBuffer out)
+ throws IOException {
+ this(out, 2048);
+ }
+
+ // ----------------------------------------------------------- Internal methods
+ /**
+ * Writes the cache out onto the underlying stream
+ * @throws IOException
+ */
+ protected void flushCache() throws IOException {
+ if (this.cachePosition > 0) {
+ this.out.writeLine(Integer.toHexString(this.cachePosition));
+ this.out.write(this.cache, 0, this.cachePosition);
+ this.out.writeLine("");
+ this.cachePosition = 0;
+ }
+ }
+
+ /**
+ * Writes the cache and bufferToAppend to the underlying stream
+ * as one large chunk
+ * @param bufferToAppend
+ * @param off
+ * @param len
+ * @throws IOException
+ */
+ protected void flushCacheWithAppend(byte bufferToAppend[], int off, int len) throws IOException {
+ this.out.writeLine(Integer.toHexString(this.cachePosition + len));
+ this.out.write(this.cache, 0, this.cachePosition);
+ this.out.write(bufferToAppend, off, len);
+ this.out.writeLine("");
+ this.cachePosition = 0;
+ }
+
+ protected void writeClosingChunk() throws IOException {
+ // Write the final chunk.
+ this.out.writeLine("0");
+ this.out.writeLine("");
+ }
+
+ // ----------------------------------------------------------- Public Methods
+ /**
+ * Must be called to ensure the internal cache is flushed and the closing chunk is written.
+ * @throws IOException
+ */
+ public void finish() throws IOException {
+ if (!this.wroteLastChunk) {
+ flushCache();
+ writeClosingChunk();
+ this.wroteLastChunk = true;
+ }
+ }
+
+ // -------------------------------------------- OutputStream Methods
+ public void write(int b) throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted write to closed stream.");
+ }
+ this.cache[this.cachePosition] = (byte) b;
+ this.cachePosition++;
+ if (this.cachePosition == this.cache.length) flushCache();
+ }
+
+ /**
+ * Writes the array. If the array does not fit within the buffer, it is
+ * not split, but rather written out as one large chunk.
+ * @param b
+ * @throws IOException
+ */
+ public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ public void write(byte src[], int off, int len) throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted write to closed stream.");
+ }
+ if (len >= this.cache.length - this.cachePosition) {
+ flushCacheWithAppend(src, off, len);
+ } else {
+ System.arraycopy(src, off, cache, this.cachePosition, len);
+ this.cachePosition += len;
+ }
+ }
+
+ /**
+ * Flushes the content buffer and the underlying stream.
+ * @throws IOException
+ */
+ public void flush() throws IOException {
+ flushCache();
+ this.out.flush();
+ }
+
+ /**
+ * Finishes writing to the underlying stream, but does NOT close the underlying stream.
+ * @throws IOException
+ */
+ public void close() throws IOException {
+ if (!this.closed) {
+ this.closed = true;
+ finish();
+ this.out.flush();
+ }
+ }
+}
diff --git a/src/org/apache/http/impl/io/ContentLengthInputStream.java b/src/org/apache/http/impl/io/ContentLengthInputStream.java
new file mode 100644
index 0000000..3b19c5b
--- /dev/null
+++ b/src/org/apache/http/impl/io/ContentLengthInputStream.java
@@ -0,0 +1,220 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java $
+ * $Revision: 652091 $
+ * $Date: 2008-04-29 13:41:07 -0700 (Tue, 29 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.http.io.SessionInputBuffer;
+
+/**
+ * Stream that cuts off after a specified number of bytes.
+ * Note that this class NEVER closes the underlying stream, even when close
+ * gets called. Instead, it will read until the "end" of its chunking on
+ * close, which allows for the seamless execution of subsequent HTTP 1.1
+ * requests, while not requiring the client to remember to read the entire
+ * contents of the response.
+ *
+ * <p>Implementation note: Choices abound. One approach would pass
+ * through the {@link InputStream#mark} and {@link InputStream#reset} calls to
+ * the underlying stream. That's tricky, though, because you then have to
+ * start duplicating the work of keeping track of how much a reset rewinds.
+ * Further, you have to watch out for the "readLimit", and since the semantics
+ * for the readLimit leave room for differing implementations, you might get
+ * into a lot of trouble.</p>
+ *
+ * <p>Alternatively, you could make this class extend
+ * {@link java.io.BufferedInputStream}
+ * and then use the protected members of that class to avoid duplicated effort.
+ * That solution has the side effect of adding yet another possible layer of
+ * buffering.</p>
+ *
+ * <p>Then, there is the simple choice, which this takes - simply don't
+ * support {@link InputStream#mark} and {@link InputStream#reset}. That choice
+ * has the added benefit of keeping this class very simple.</p>
+ *
+ * @author Ortwin Glueck
+ * @author Eric Johnson
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @since 4.0
+ */
+public class ContentLengthInputStream extends InputStream {
+
+ private static final int BUFFER_SIZE = 2048;
+ /**
+ * The maximum number of bytes that can be read from the stream. Subsequent
+ * read operations will return -1.
+ */
+ private long contentLength;
+
+ /** The current position */
+ private long pos = 0;
+
+ /** True if the stream is closed. */
+ private boolean closed = false;
+
+ /**
+ * Wrapped input stream that all calls are delegated to.
+ */
+ private SessionInputBuffer in = null;
+
+ /**
+ * Creates a new length limited stream
+ *
+ * @param in The session input buffer to wrap
+ * @param contentLength The maximum number of bytes that can be read from
+ * the stream. Subsequent read operations will return -1.
+ */
+ public ContentLengthInputStream(final SessionInputBuffer in, long contentLength) {
+ super();
+ if (in == null) {
+ throw new IllegalArgumentException("Input stream may not be null");
+ }
+ if (contentLength < 0) {
+ throw new IllegalArgumentException("Content length may not be negative");
+ }
+ this.in = in;
+ this.contentLength = contentLength;
+ }
+
+ /**
+ * <p>Reads until the end of the known length of content.</p>
+ *
+ * <p>Does not close the underlying socket input, but instead leaves it
+ * primed to parse the next response.</p>
+ * @throws IOException If an IO problem occurs.
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ try {
+ byte buffer[] = new byte[BUFFER_SIZE];
+ while (read(buffer) >= 0) {
+ }
+ } finally {
+ // close after above so that we don't throw an exception trying
+ // to read after closed!
+ closed = true;
+ }
+ }
+ }
+
+
+ /**
+ * Read the next byte from the stream
+ * @return The next byte or -1 if the end of stream has been reached.
+ * @throws IOException If an IO problem occurs
+ * @see java.io.InputStream#read()
+ */
+ public int read() throws IOException {
+ if (closed) {
+ throw new IOException("Attempted read from closed stream.");
+ }
+
+ if (pos >= contentLength) {
+ return -1;
+ }
+ pos++;
+ return this.in.read();
+ }
+
+ /**
+ * Does standard {@link InputStream#read(byte[], int, int)} behavior, but
+ * also notifies the watcher when the contents have been consumed.
+ *
+ * @param b The byte array to fill.
+ * @param off Start filling at this position.
+ * @param len The number of bytes to attempt to read.
+ * @return The number of bytes read, or -1 if the end of content has been
+ * reached.
+ *
+ * @throws java.io.IOException Should an error occur on the wrapped stream.
+ */
+ public int read (byte[] b, int off, int len) throws java.io.IOException {
+ if (closed) {
+ throw new IOException("Attempted read from closed stream.");
+ }
+
+ if (pos >= contentLength) {
+ return -1;
+ }
+
+ if (pos + len > contentLength) {
+ len = (int) (contentLength - pos);
+ }
+ int count = this.in.read(b, off, len);
+ pos += count;
+ return count;
+ }
+
+
+ /**
+ * Read more bytes from the stream.
+ * @param b The byte array to put the new data in.
+ * @return The number of bytes read into the buffer.
+ * @throws IOException If an IO problem occurs
+ * @see java.io.InputStream#read(byte[])
+ */
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Skips and discards a number of bytes from the input stream.
+ * @param n The number of bytes to skip.
+ * @return The actual number of bytes skipped. <= 0 if no bytes
+ * are skipped.
+ * @throws IOException If an error occurs while skipping bytes.
+ * @see InputStream#skip(long)
+ */
+ public long skip(long n) throws IOException {
+ if (n <= 0) {
+ return 0;
+ }
+ byte[] buffer = new byte[BUFFER_SIZE];
+ // make sure we don't skip more bytes than are
+ // still available
+ long remaining = Math.min(n, this.contentLength - this.pos);
+ // skip and keep track of the bytes actually skipped
+ long count = 0;
+ while (remaining > 0) {
+ int l = read(buffer, 0, (int)Math.min(BUFFER_SIZE, remaining));
+ if (l == -1) {
+ break;
+ }
+ count += l;
+ remaining -= l;
+ }
+ this.pos += count;
+ return count;
+ }
+}
diff --git a/src/org/apache/http/impl/io/ContentLengthOutputStream.java b/src/org/apache/http/impl/io/ContentLengthOutputStream.java
new file mode 100644
index 0000000..afcb883
--- /dev/null
+++ b/src/org/apache/http/impl/io/ContentLengthOutputStream.java
@@ -0,0 +1,132 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ContentLengthOutputStream.java $
+ * $Revision: 560343 $
+ * $Date: 2007-07-27 11:18:19 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.http.io.SessionOutputBuffer;
+
+/**
+ * A stream wrapper that closes itself after a defined number of bytes.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560343 $
+ *
+ * @since 4.0
+ */
+public class ContentLengthOutputStream extends OutputStream {
+
+ /**
+ * Wrapped session outbut buffer.
+ */
+ private final SessionOutputBuffer out;
+
+ /**
+ * The maximum number of bytes that can be written the stream. Subsequent
+ * write operations will be ignored.
+ */
+ private final long contentLength;
+
+ /** Total bytes written */
+ private long total = 0;
+
+ /** True if the stream is closed. */
+ private boolean closed = false;
+
+ /**
+ * Creates a new length limited stream
+ *
+ * @param out The data transmitter to wrap
+ * @param contentLength The maximum number of bytes that can be written to
+ * the stream. Subsequent write operations will be ignored.
+ *
+ * @since 4.0
+ */
+ public ContentLengthOutputStream(final SessionOutputBuffer out, long contentLength) {
+ super();
+ if (out == null) {
+ throw new IllegalArgumentException("Session output buffer may not be null");
+ }
+ if (contentLength < 0) {
+ throw new IllegalArgumentException("Content length may not be negative");
+ }
+ this.out = out;
+ this.contentLength = contentLength;
+ }
+
+ /**
+ * <p>Does not close the underlying socket output.</p>
+ *
+ * @throws IOException If an I/O problem occurs.
+ */
+ public void close() throws IOException {
+ if (!this.closed) {
+ this.closed = true;
+ this.out.flush();
+ }
+ }
+
+ public void flush() throws IOException {
+ this.out.flush();
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted write to closed stream.");
+ }
+ if (this.total < this.contentLength) {
+ long max = this.contentLength - this.total;
+ if (len > max) {
+ len = (int) max;
+ }
+ this.out.write(b, off, len);
+ this.total += len;
+ }
+ }
+
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ public void write(int b) throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted write to closed stream.");
+ }
+ if (this.total < this.contentLength) {
+ this.out.write(b);
+ this.total++;
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/HttpRequestParser.java b/src/org/apache/http/impl/io/HttpRequestParser.java
new file mode 100644
index 0000000..a7bae6d
--- /dev/null
+++ b/src/org/apache/http/impl/io/HttpRequestParser.java
@@ -0,0 +1,80 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpRequestParser.java $
+ * $Revision: 589374 $
+ * $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+
+import org.apache.http.ConnectionClosedException;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpRequestFactory;
+import org.apache.http.RequestLine;
+import org.apache.http.ParseException;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.message.LineParser;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+public class HttpRequestParser extends AbstractMessageParser {
+
+ private final HttpRequestFactory requestFactory;
+ private final CharArrayBuffer lineBuf;
+
+ public HttpRequestParser(
+ final SessionInputBuffer buffer,
+ final LineParser parser,
+ final HttpRequestFactory requestFactory,
+ final HttpParams params) {
+ super(buffer, parser, params);
+ if (requestFactory == null) {
+ throw new IllegalArgumentException("Request factory may not be null");
+ }
+ this.requestFactory = requestFactory;
+ this.lineBuf = new CharArrayBuffer(128);
+ }
+
+ protected HttpMessage parseHead(
+ final SessionInputBuffer sessionBuffer)
+ throws IOException, HttpException, ParseException {
+
+ this.lineBuf.clear();
+ int i = sessionBuffer.readLine(this.lineBuf);
+ if (i == -1) {
+ throw new ConnectionClosedException("Client closed connection");
+ }
+ ParserCursor cursor = new ParserCursor(0, this.lineBuf.length());
+ RequestLine requestline = this.lineParser.parseRequestLine(this.lineBuf, cursor);
+ return this.requestFactory.newHttpRequest(requestline);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/HttpRequestWriter.java b/src/org/apache/http/impl/io/HttpRequestWriter.java
new file mode 100644
index 0000000..b784e2d
--- /dev/null
+++ b/src/org/apache/http/impl/io/HttpRequestWriter.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpRequestWriter.java $
+ * $Revision: 569673 $
+ * $Date: 2007-08-25 06:58:51 -0700 (Sat, 25 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpRequest;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.message.LineFormatter;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+public class HttpRequestWriter extends AbstractMessageWriter {
+
+ public HttpRequestWriter(final SessionOutputBuffer buffer,
+ final LineFormatter formatter,
+ final HttpParams params) {
+ super(buffer, formatter, params);
+ }
+
+ protected void writeHeadLine(final HttpMessage message)
+ throws IOException {
+
+ final CharArrayBuffer buffer = lineFormatter.formatRequestLine
+ (this.lineBuf, ((HttpRequest) message).getRequestLine());
+ this.sessionBuffer.writeLine(buffer);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/HttpResponseParser.java b/src/org/apache/http/impl/io/HttpResponseParser.java
new file mode 100644
index 0000000..575aa18
--- /dev/null
+++ b/src/org/apache/http/impl/io/HttpResponseParser.java
@@ -0,0 +1,81 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpResponseParser.java $
+ * $Revision: 589374 $
+ * $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.NoHttpResponseException;
+import org.apache.http.StatusLine;
+import org.apache.http.ParseException;
+import org.apache.http.io.SessionInputBuffer;
+import org.apache.http.message.LineParser;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+public class HttpResponseParser extends AbstractMessageParser {
+
+ private final HttpResponseFactory responseFactory;
+ private final CharArrayBuffer lineBuf;
+
+ public HttpResponseParser(
+ final SessionInputBuffer buffer,
+ final LineParser parser,
+ final HttpResponseFactory responseFactory,
+ final HttpParams params) {
+ super(buffer, parser, params);
+ if (responseFactory == null) {
+ throw new IllegalArgumentException("Response factory may not be null");
+ }
+ this.responseFactory = responseFactory;
+ this.lineBuf = new CharArrayBuffer(128);
+ }
+
+ protected HttpMessage parseHead(
+ final SessionInputBuffer sessionBuffer)
+ throws IOException, HttpException, ParseException {
+
+ this.lineBuf.clear();
+ int i = sessionBuffer.readLine(this.lineBuf);
+ if (i == -1) {
+ throw new NoHttpResponseException("The target server failed to respond");
+ }
+ //create the status line from the status string
+ ParserCursor cursor = new ParserCursor(0, this.lineBuf.length());
+ StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor);
+ return this.responseFactory.newHttpResponse(statusline, null);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/HttpResponseWriter.java b/src/org/apache/http/impl/io/HttpResponseWriter.java
new file mode 100644
index 0000000..f88791e
--- /dev/null
+++ b/src/org/apache/http/impl/io/HttpResponseWriter.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpResponseWriter.java $
+ * $Revision: 569673 $
+ * $Date: 2007-08-25 06:58:51 -0700 (Sat, 25 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpResponse;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.message.LineFormatter;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.CharArrayBuffer;
+
+public class HttpResponseWriter extends AbstractMessageWriter {
+
+ public HttpResponseWriter(final SessionOutputBuffer buffer,
+ final LineFormatter formatter,
+ final HttpParams params) {
+ super(buffer, formatter, params);
+ }
+
+ protected void writeHeadLine(final HttpMessage message)
+ throws IOException {
+
+ final CharArrayBuffer buffer = lineFormatter.formatStatusLine
+ (this.lineBuf, ((HttpResponse) message).getStatusLine());
+ this.sessionBuffer.writeLine(buffer);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/HttpTransportMetricsImpl.java b/src/org/apache/http/impl/io/HttpTransportMetricsImpl.java
new file mode 100644
index 0000000..53e6772
--- /dev/null
+++ b/src/org/apache/http/impl/io/HttpTransportMetricsImpl.java
@@ -0,0 +1,63 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpTransportMetricsImpl.java $
+ * $Revision: 539755 $
+ * $Date: 2007-05-19 07:05:02 -0700 (Sat, 19 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import org.apache.http.io.HttpTransportMetrics;
+
+/**
+ * Default implementation of {@link HttpTransportMetrics}.
+ */
+public class HttpTransportMetricsImpl implements HttpTransportMetrics {
+
+ private long bytesTransferred = 0;
+
+ public HttpTransportMetricsImpl() {
+ super();
+ }
+
+ public long getBytesTransferred() {
+ return this.bytesTransferred;
+ }
+
+ public void setBytesTransferred(long count) {
+ this.bytesTransferred = count;
+ }
+
+ public void incrementBytesTransferred(long count) {
+ this.bytesTransferred += count;
+ }
+
+ public void reset() {
+ this.bytesTransferred = 0;
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/IdentityInputStream.java b/src/org/apache/http/impl/io/IdentityInputStream.java
new file mode 100644
index 0000000..390d5b7
--- /dev/null
+++ b/src/org/apache/http/impl/io/IdentityInputStream.java
@@ -0,0 +1,90 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/IdentityInputStream.java $
+ * $Revision: 560358 $
+ * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.http.io.SessionInputBuffer;
+
+/**
+ * A stream for reading from a {@link SessionInputBuffer session input buffer}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560358 $
+ *
+ * @since 4.0
+ */
+public class IdentityInputStream extends InputStream {
+
+ private final SessionInputBuffer in;
+
+ private boolean closed = false;
+
+ public IdentityInputStream(final SessionInputBuffer in) {
+ super();
+ if (in == null) {
+ throw new IllegalArgumentException("Session input buffer may not be null");
+ }
+ this.in = in;
+ }
+
+ public int available() throws IOException {
+ if (!this.closed && this.in.isDataAvailable(10)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ public void close() throws IOException {
+ this.closed = true;
+ }
+
+ public int read() throws IOException {
+ if (this.closed) {
+ return -1;
+ } else {
+ return this.in.read();
+ }
+ }
+
+ public int read(final byte[] b, int off, int len) throws IOException {
+ if (this.closed) {
+ return -1;
+ } else {
+ return this.in.read(b, off, len);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/IdentityOutputStream.java b/src/org/apache/http/impl/io/IdentityOutputStream.java
new file mode 100644
index 0000000..10b64f7
--- /dev/null
+++ b/src/org/apache/http/impl/io/IdentityOutputStream.java
@@ -0,0 +1,100 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/IdentityOutputStream.java $
+ * $Revision: 560343 $
+ * $Date: 2007-07-27 11:18:19 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.http.io.SessionOutputBuffer;
+
+/**
+ * A stream for writing with an "identity" transport encoding.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560343 $
+ *
+ * @since 4.0
+ */
+public class IdentityOutputStream extends OutputStream {
+
+ /**
+ * Wrapped session output buffer.
+ */
+ private final SessionOutputBuffer out;
+
+ /** True if the stream is closed. */
+ private boolean closed = false;
+
+ public IdentityOutputStream(final SessionOutputBuffer out) {
+ super();
+ if (out == null) {
+ throw new IllegalArgumentException("Session output buffer may not be null");
+ }
+ this.out = out;
+ }
+
+ /**
+ * <p>Does not close the underlying socket output.</p>
+ *
+ * @throws IOException If an I/O problem occurs.
+ */
+ public void close() throws IOException {
+ if (!this.closed) {
+ this.closed = true;
+ this.out.flush();
+ }
+ }
+
+ public void flush() throws IOException {
+ this.out.flush();
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted write to closed stream.");
+ }
+ this.out.write(b, off, len);
+ }
+
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ public void write(int b) throws IOException {
+ if (this.closed) {
+ throw new IOException("Attempted write to closed stream.");
+ }
+ this.out.write(b);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/SocketInputBuffer.java b/src/org/apache/http/impl/io/SocketInputBuffer.java
new file mode 100644
index 0000000..925e80a
--- /dev/null
+++ b/src/org/apache/http/impl/io/SocketInputBuffer.java
@@ -0,0 +1,115 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/SocketInputBuffer.java $
+ * $Revision: 560358 $
+ * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.Socket;
+
+import org.apache.http.params.HttpParams;
+
+
+/**
+ * {@link Socket} bound session input buffer.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560358 $
+ *
+ * @since 4.0
+ */
+public class SocketInputBuffer extends AbstractSessionInputBuffer {
+
+ static private final Class SOCKET_TIMEOUT_CLASS = SocketTimeoutExceptionClass();
+
+ /**
+ * Returns <code>SocketTimeoutExceptionClass<code> or <code>null</code> if the class
+ * does not exist.
+ *
+ * @return <code>SocketTimeoutExceptionClass<code>, or <code>null</code> if unavailable.
+ */
+ static private Class SocketTimeoutExceptionClass() {
+ try {
+ return Class.forName("java.net.SocketTimeoutException");
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ private static boolean isSocketTimeoutException(final InterruptedIOException e) {
+ if (SOCKET_TIMEOUT_CLASS != null) {
+ return SOCKET_TIMEOUT_CLASS.isInstance(e);
+ } else {
+ return true;
+ }
+ }
+
+ private final Socket socket;
+
+ public SocketInputBuffer(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ super();
+ if (socket == null) {
+ throw new IllegalArgumentException("Socket may not be null");
+ }
+ this.socket = socket;
+ if (buffersize < 0) {
+ buffersize = socket.getReceiveBufferSize();
+ }
+ if (buffersize < 1024) {
+ buffersize = 1024;
+ }
+ init(socket.getInputStream(), buffersize, params);
+ }
+
+ public boolean isDataAvailable(int timeout) throws IOException {
+ boolean result = hasBufferedData();
+ if (!result) {
+ int oldtimeout = this.socket.getSoTimeout();
+ try {
+ this.socket.setSoTimeout(timeout);
+ fillBuffer();
+ result = hasBufferedData();
+ } catch (InterruptedIOException e) {
+ if (!isSocketTimeoutException(e)) {
+ throw e;
+ }
+ } finally {
+ socket.setSoTimeout(oldtimeout);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/SocketOutputBuffer.java b/src/org/apache/http/impl/io/SocketOutputBuffer.java
new file mode 100644
index 0000000..efb91e9
--- /dev/null
+++ b/src/org/apache/http/impl/io/SocketOutputBuffer.java
@@ -0,0 +1,79 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/SocketOutputBuffer.java $
+ * $Revision: 560358 $
+ * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.io;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.http.params.HttpParams;
+
+
+/**
+ * {@link Socket} bound session output buffer.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560358 $
+ *
+ * @since 4.0
+ */
+public class SocketOutputBuffer extends AbstractSessionOutputBuffer {
+
+ public SocketOutputBuffer(
+ final Socket socket,
+ int buffersize,
+ final HttpParams params) throws IOException {
+ super();
+ if (socket == null) {
+ throw new IllegalArgumentException("Socket may not be null");
+ }
+ if (buffersize < 0) {
+ buffersize = socket.getReceiveBufferSize();
+// BEGIN android-changed
+ // Workaround for http://b/issue?id=1083103.
+ if (buffersize > 8096) {
+ buffersize = 8096;
+ }
+// END android-changed
+ }
+ if (buffersize < 1024) {
+ buffersize = 1024;
+ }
+
+// BEGIN android-changed
+ socket.setSendBufferSize(buffersize * 3);
+// END andrdoid-changed
+
+ init(socket.getOutputStream(), buffersize, params);
+ }
+
+}
diff --git a/src/org/apache/http/impl/io/package.html b/src/org/apache/http/impl/io/package.html
new file mode 100644
index 0000000..48eb2c1
--- /dev/null
+++ b/src/org/apache/http/impl/io/package.html
@@ -0,0 +1,48 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/package.html $
+ * $Revision: 567360 $
+ * $Date: 2007-08-18 23:49:21 -0700 (Sat, 18 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Default implementations for interfaces in
+{@link org.apache.http.io org.apache.http.io}.
+
+<br/>
+
+There are implementations of the transport encodings used by HTTP,
+in particular the chunked encoding for
+{@link org.apache.http.impl.io.ChunkedOutputStream sending} and
+{@link org.apache.http.impl.io.ChunkedInputStream receiving} entities.
+
+</body>
+</html>
diff --git a/src/org/apache/http/impl/package.html b/src/org/apache/http/impl/package.html
new file mode 100644
index 0000000..6cec586
--- /dev/null
+++ b/src/org/apache/http/impl/package.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/package.html $
+ * $Revision: 496072 $
+ * $Date: 2007-01-14 04:22:55 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Default implementations for interfaces in
+{@link org.apache.http org.apache.http}.
+
+</body>
+</html>
diff --git a/src/org/apache/http/io/HttpMessageParser.java b/src/org/apache/http/io/HttpMessageParser.java
new file mode 100644
index 0000000..5c24736
--- /dev/null
+++ b/src/org/apache/http/io/HttpMessageParser.java
@@ -0,0 +1,53 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/io/HttpMessageParser.java $
+ * $Revision: 567370 $
+ * $Date: 2007-08-19 01:13:21 -0700 (Sun, 19 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.io;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+
+/**
+ * Generic message parser interface.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 567370 $
+ *
+ * @since 4.0
+ */
+public interface HttpMessageParser {
+
+ HttpMessage parse()
+ throws IOException, HttpException;
+
+}
diff --git a/src/org/apache/http/io/HttpMessageWriter.java b/src/org/apache/http/io/HttpMessageWriter.java
new file mode 100644
index 0000000..b6ac7c1
--- /dev/null
+++ b/src/org/apache/http/io/HttpMessageWriter.java
@@ -0,0 +1,53 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/io/HttpMessageWriter.java $
+ * $Revision: 567370 $
+ * $Date: 2007-08-19 01:13:21 -0700 (Sun, 19 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.io;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpMessage;
+
+/**
+ * Generic message writer interface.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 567370 $
+ *
+ * @since 4.0
+ */
+public interface HttpMessageWriter {
+
+ void write(HttpMessage message)
+ throws IOException, HttpException;
+
+}
diff --git a/src/org/apache/http/io/HttpTransportMetrics.java b/src/org/apache/http/io/HttpTransportMetrics.java
new file mode 100644
index 0000000..f88e036
--- /dev/null
+++ b/src/org/apache/http/io/HttpTransportMetrics.java
@@ -0,0 +1,46 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/io/HttpTransportMetrics.java $
+ * $Revision: 536667 $
+ * $Date: 2007-05-09 14:48:41 -0700 (Wed, 09 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.io;
+
+public interface HttpTransportMetrics {
+
+ /**
+ * Returns the number of bytes trasferred.
+ */
+ long getBytesTransferred();
+
+ /**
+ * Resets the counts
+ */
+ void reset();
+
+}
diff --git a/src/org/apache/http/io/SessionInputBuffer.java b/src/org/apache/http/io/SessionInputBuffer.java
new file mode 100644
index 0000000..d7824d9
--- /dev/null
+++ b/src/org/apache/http/io/SessionInputBuffer.java
@@ -0,0 +1,63 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/io/SessionInputBuffer.java $
+ * $Revision: 560528 $
+ * $Date: 2007-07-28 04:34:17 -0700 (Sat, 28 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.io;
+
+import java.io.IOException;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Session input buffer for blocking connections.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560528 $
+ *
+ * @since 4.0
+ */
+public interface SessionInputBuffer {
+
+ int read(byte[] b, int off, int len) throws IOException;
+
+ int read(byte[] b) throws IOException;
+
+ int read() throws IOException;
+
+ int readLine(CharArrayBuffer buffer) throws IOException;
+
+ String readLine() throws IOException;
+
+ boolean isDataAvailable(int timeout) throws IOException;
+
+ HttpTransportMetrics getMetrics();
+
+}
diff --git a/src/org/apache/http/io/SessionOutputBuffer.java b/src/org/apache/http/io/SessionOutputBuffer.java
new file mode 100644
index 0000000..6587a26
--- /dev/null
+++ b/src/org/apache/http/io/SessionOutputBuffer.java
@@ -0,0 +1,63 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/io/SessionOutputBuffer.java $
+ * $Revision: 560528 $
+ * $Date: 2007-07-28 04:34:17 -0700 (Sat, 28 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.io;
+
+import java.io.IOException;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Session output buffer for blocking connections.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 560528 $
+ *
+ * @since 4.0
+ */
+public interface SessionOutputBuffer {
+
+ void write(byte[] b, int off, int len) throws IOException;
+
+ void write(byte[] b) throws IOException;
+
+ void write(int b) throws IOException;
+
+ void writeLine(String s) throws IOException;
+
+ void writeLine(CharArrayBuffer buffer) throws IOException;
+
+ void flush() throws IOException;
+
+ HttpTransportMetrics getMetrics();
+
+}
diff --git a/src/org/apache/http/io/package.html b/src/org/apache/http/io/package.html
new file mode 100644
index 0000000..da9fabf
--- /dev/null
+++ b/src/org/apache/http/io/package.html
@@ -0,0 +1,47 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/io/package.html $
+ * $Revision: 503192 $
+ * $Date: 2007-02-03 03:55:49 -0800 (Sat, 03 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The transport layer abstraction of the HTTP components.
+
+This layer is used to transfer messages over connections.
+Connections are typically based on sockets: plain or secure,
+direct or via SOCKS hosts, with bandwidth throttling, or
+whatever else you might think of.
+However, opening connections is not within the responsibility
+of HttpCore.
+
+</body>
+</html>
diff --git a/src/org/apache/http/message/AbstractHttpMessage.java b/src/org/apache/http/message/AbstractHttpMessage.java
new file mode 100644
index 0000000..d8a6962
--- /dev/null
+++ b/src/org/apache/http/message/AbstractHttpMessage.java
@@ -0,0 +1,166 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/AbstractHttpMessage.java $
+ * $Revision: 620287 $
+ * $Date: 2008-02-10 07:15:53 -0800 (Sun, 10 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.Iterator;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpMessage;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.BasicHttpParams;
+
+/**
+ * Basic implementation of an HTTP message that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 620287 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractHttpMessage implements HttpMessage {
+
+ protected HeaderGroup headergroup;
+
+ protected HttpParams params;
+
+ protected AbstractHttpMessage(final HttpParams params) {
+ super();
+ this.headergroup = new HeaderGroup();
+ this.params = params;
+ }
+
+ protected AbstractHttpMessage() {
+ this(null);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public boolean containsHeader(String name) {
+ return this.headergroup.containsHeader(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header[] getHeaders(final String name) {
+ return this.headergroup.getHeaders(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header getFirstHeader(final String name) {
+ return this.headergroup.getFirstHeader(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header getLastHeader(final String name) {
+ return this.headergroup.getLastHeader(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header[] getAllHeaders() {
+ return this.headergroup.getAllHeaders();
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void addHeader(final Header header) {
+ this.headergroup.addHeader(header);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void addHeader(final String name, final String value) {
+ if (name == null) {
+ throw new IllegalArgumentException("Header name may not be null");
+ }
+ this.headergroup.addHeader(new BasicHeader(name, value));
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setHeader(final Header header) {
+ this.headergroup.updateHeader(header);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setHeader(final String name, final String value) {
+ if (name == null) {
+ throw new IllegalArgumentException("Header name may not be null");
+ }
+ this.headergroup.updateHeader(new BasicHeader(name, value));
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setHeaders(final Header[] headers) {
+ this.headergroup.setHeaders(headers);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void removeHeader(final Header header) {
+ this.headergroup.removeHeader(header);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void removeHeaders(final String name) {
+ if (name == null) {
+ return;
+ }
+ for (Iterator i = this.headergroup.iterator(); i.hasNext(); ) {
+ Header header = (Header) i.next();
+ if (name.equalsIgnoreCase(header.getName())) {
+ i.remove();
+ }
+ }
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public HeaderIterator headerIterator() {
+ return this.headergroup.iterator();
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public HeaderIterator headerIterator(String name) {
+ return this.headergroup.iterator(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public HttpParams getParams() {
+ if (this.params == null) {
+ this.params = new BasicHttpParams();
+ }
+ return this.params;
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setParams(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.params = params;
+ }
+}
diff --git a/src/org/apache/http/message/BasicHeader.java b/src/org/apache/http/message/BasicHeader.java
new file mode 100644
index 0000000..f134d8d
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeader.java
@@ -0,0 +1,143 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeader.java $
+ * $Revision: 652956 $
+ * $Date: 2008-05-02 17:13:05 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.ParseException;
+
+/**
+ * Represents an HTTP header field.
+ *
+ * <p>The HTTP header fields follow the same generic format as
+ * that given in Section 3.1 of RFC 822. Each header field consists
+ * of a name followed by a colon (":") and the field value. Field names
+ * are case-insensitive. The field value MAY be preceded by any amount
+ * of LWS, though a single SP is preferred.
+ *
+ *<pre>
+ * message-header = field-name ":" [ field-value ]
+ * field-name = token
+ * field-value = *( field-content | LWS )
+ * field-content = &lt;the OCTETs making up the field-value
+ * and consisting of either *TEXT or combinations
+ * of token, separators, and quoted-string&gt;
+ *</pre>
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 652956 $ $Date: 2008-05-02 17:13:05 -0700 (Fri, 02 May 2008) $
+ *
+ * @since 4.0
+ */
+public class BasicHeader implements Header, Cloneable {
+
+ /**
+ * Header name.
+ */
+ private final String name;
+
+ /**
+ * Header value.
+ */
+ private final String value;
+
+ /**
+ * Constructor with name and value
+ *
+ * @param name the header name
+ * @param value the header value
+ */
+ public BasicHeader(final String name, final String value) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns the header name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the header value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+ /**
+ * Returns a {@link String} representation of the header.
+ *
+ * @return a string
+ */
+ public String toString() {
+ // no need for non-default formatting in toString()
+ return BasicLineFormatter.DEFAULT.formatHeader(null, this).toString();
+ }
+
+ /**
+ * Returns an array of {@link HeaderElement}s constructed from my value.
+ *
+ * @see BasicHeaderValueParser#parseElements(String, HeaderValueParser)
+ *
+ * @return an array of header elements
+ *
+ * @throws ParseException in case of a parse error
+ */
+ public HeaderElement[] getElements() throws ParseException {
+ if (this.value != null) {
+ // result intentionally not cached, it's probably not used again
+ return BasicHeaderValueParser.parseElements(this.value, null);
+ } else {
+ return new HeaderElement[] {};
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicHeaderElement.java b/src/org/apache/http/message/BasicHeaderElement.java
new file mode 100644
index 0000000..19a40c6
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderElement.java
@@ -0,0 +1,243 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderElement.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.LangUtils;
+
+/**
+ * One element of an HTTP header's value.
+ * <p>
+ * Some HTTP headers (such as the set-cookie header) have values that
+ * can be decomposed into multiple elements. Such headers must be in the
+ * following form:
+ * </p>
+ * <pre>
+ * header = [ element ] *( "," [ element ] )
+ * element = name [ "=" [ value ] ] *( ";" [ param ] )
+ * param = name [ "=" [ value ] ]
+ *
+ * name = token
+ * value = ( token | quoted-string )
+ *
+ * token = 1*&lt;any char except "=", ",", ";", &lt;"&gt; and
+ * white space&gt;
+ * quoted-string = &lt;"&gt; *( text | quoted-char ) &lt;"&gt;
+ * text = any char except &lt;"&gt;
+ * quoted-char = "\" char
+ * </pre>
+ * <p>
+ * Any amount of white space is allowed between any part of the
+ * header, element or param and is ignored. A missing value in any
+ * element or param will be stored as the empty {@link String};
+ * if the "=" is also missing <var>null</var> will be stored instead.
+ * </p>
+ * <p>
+ * This class represents an individual header element, containing
+ * both a name/value pair (value may be <tt>null</tt>) and optionally
+ * a set of additional parameters.
+ * </p>
+ *
+ * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 604625 $ $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * @since 4.0
+ */
+public class BasicHeaderElement implements HeaderElement, Cloneable {
+
+ private final String name;
+ private final String value;
+ private final NameValuePair[] parameters;
+
+ /**
+ * Constructor with name, value and parameters.
+ *
+ * @param name header element name
+ * @param value header element value. May be <tt>null</tt>
+ * @param parameters header element parameters. May be <tt>null</tt>.
+ * Parameters are copied by reference, not by value
+ */
+ public BasicHeaderElement(
+ final String name,
+ final String value,
+ final NameValuePair[] parameters) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.value = value;
+ if (parameters != null) {
+ this.parameters = parameters;
+ } else {
+ this.parameters = new NameValuePair[] {};
+ }
+ }
+
+ /**
+ * Constructor with name and value.
+ *
+ * @param name header element name
+ * @param value header element value. May be <tt>null</tt>
+ */
+ public BasicHeaderElement(final String name, final String value) {
+ this(name, value, null);
+ }
+
+ /**
+ * Returns the name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+ /**
+ * Get parameters, if any.
+ * The returned array is created for each invocation and can
+ * be modified by the caller without affecting this header element.
+ *
+ * @return parameters as an array of {@link NameValuePair}s
+ */
+ public NameValuePair[] getParameters() {
+ return (NameValuePair[])this.parameters.clone();
+ }
+
+
+ /**
+ * Obtains the number of parameters.
+ *
+ * @return the number of parameters
+ */
+ public int getParameterCount() {
+ return this.parameters.length;
+ }
+
+
+ /**
+ * Obtains the parameter with the given index.
+ *
+ * @param index the index of the parameter, 0-based
+ *
+ * @return the parameter with the given index
+ */
+ public NameValuePair getParameter(int index) {
+ // ArrayIndexOutOfBoundsException is appropriate
+ return this.parameters[index];
+ }
+
+
+ /**
+ * Returns parameter with the given name, if found. Otherwise null
+ * is returned
+ *
+ * @param name The name to search by.
+ * @return NameValuePair parameter with the given name
+ */
+ public NameValuePair getParameterByName(final String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ NameValuePair found = null;
+ for (int i = 0; i < this.parameters.length; i++) {
+ NameValuePair current = this.parameters[ i ];
+ if (current.getName().equalsIgnoreCase(name)) {
+ found = current;
+ break;
+ }
+ }
+ return found;
+ }
+
+ public boolean equals(final Object object) {
+ if (object == null) return false;
+ if (this == object) return true;
+ if (object instanceof HeaderElement) {
+ BasicHeaderElement that = (BasicHeaderElement) object;
+ return this.name.equals(that.name)
+ && LangUtils.equals(this.value, that.value)
+ && LangUtils.equals(this.parameters, that.parameters);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.name);
+ hash = LangUtils.hashCode(hash, this.value);
+ for (int i = 0; i < this.parameters.length; i++) {
+ hash = LangUtils.hashCode(hash, this.parameters[i]);
+ }
+ return hash;
+ }
+
+ public String toString() {
+ CharArrayBuffer buffer = new CharArrayBuffer(64);
+ buffer.append(this.name);
+ if (this.value != null) {
+ buffer.append("=");
+ buffer.append(this.value);
+ }
+ for (int i = 0; i < this.parameters.length; i++) {
+ buffer.append("; ");
+ buffer.append(this.parameters[i]);
+ }
+ return buffer.toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ // parameters array is considered immutable
+ // no need to make a copy of it
+ return super.clone();
+ }
+
+}
+
diff --git a/src/org/apache/http/message/BasicHeaderElementIterator.java b/src/org/apache/http/message/BasicHeaderElementIterator.java
new file mode 100644
index 0000000..46f53a8
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderElementIterator.java
@@ -0,0 +1,161 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderElementIterator.java $
+ * $Revision: 592088 $
+ * $Date: 2007-11-05 09:03:39 -0800 (Mon, 05 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.NoSuchElementException;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HeaderElementIterator;
+import org.apache.http.HeaderIterator;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Basic implementation of a {@link HeaderElementIterator}.
+ *
+ * @version $Revision: 592088 $
+ *
+ * @author Andrea Selva <selva.andre at gmail.com>
+ * @author Oleg Kalnichevski <oleg at ural.ru>
+ */
+public class BasicHeaderElementIterator implements HeaderElementIterator {
+
+ private final HeaderIterator headerIt;
+ private final HeaderValueParser parser;
+
+ private HeaderElement currentElement = null;
+ private CharArrayBuffer buffer = null;
+ private ParserCursor cursor = null;
+
+ /**
+ * Creates a new instance of BasicHeaderElementIterator
+ */
+ public BasicHeaderElementIterator(
+ final HeaderIterator headerIterator,
+ final HeaderValueParser parser) {
+ if (headerIterator == null) {
+ throw new IllegalArgumentException("Header iterator may not be null");
+ }
+ if (parser == null) {
+ throw new IllegalArgumentException("Parser may not be null");
+ }
+ this.headerIt = headerIterator;
+ this.parser = parser;
+ }
+
+
+ public BasicHeaderElementIterator(final HeaderIterator headerIterator) {
+ this(headerIterator, BasicHeaderValueParser.DEFAULT);
+ }
+
+
+ private void bufferHeaderValue() {
+ this.cursor = null;
+ this.buffer = null;
+ while (this.headerIt.hasNext()) {
+ Header h = this.headerIt.nextHeader();
+ if (h instanceof FormattedHeader) {
+ this.buffer = ((FormattedHeader) h).getBuffer();
+ this.cursor = new ParserCursor(0, this.buffer.length());
+ this.cursor.updatePos(((FormattedHeader) h).getValuePos());
+ break;
+ } else {
+ String value = h.getValue();
+ if (value != null) {
+ this.buffer = new CharArrayBuffer(value.length());
+ this.buffer.append(value);
+ this.cursor = new ParserCursor(0, this.buffer.length());
+ break;
+ }
+ }
+ }
+ }
+
+ private void parseNextElement() {
+ // loop while there are headers left to parse
+ while (this.headerIt.hasNext() || this.cursor != null) {
+ if (this.cursor == null || this.cursor.atEnd()) {
+ // get next header value
+ bufferHeaderValue();
+ }
+ // Anything buffered?
+ if (this.cursor != null) {
+ // loop while there is data in the buffer
+ while (!this.cursor.atEnd()) {
+ HeaderElement e = this.parser.parseHeaderElement(this.buffer, this.cursor);
+ if (!(e.getName().length() == 0 && e.getValue() == null)) {
+ // Found something
+ this.currentElement = e;
+ return;
+ }
+ }
+ // if at the end of the buffer
+ if (this.cursor.atEnd()) {
+ // discard it
+ this.cursor = null;
+ this.buffer = null;
+ }
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ if (this.currentElement == null) {
+ parseNextElement();
+ }
+ return this.currentElement != null;
+ }
+
+ public HeaderElement nextElement() throws NoSuchElementException {
+ if (this.currentElement == null) {
+ parseNextElement();
+ }
+
+ if (this.currentElement == null) {
+ throw new NoSuchElementException("No more header elements available");
+ }
+
+ HeaderElement element = this.currentElement;
+ this.currentElement = null;
+ return element;
+ }
+
+ public final Object next() throws NoSuchElementException {
+ return nextElement();
+ }
+
+ public void remove() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+
+} \ No newline at end of file
diff --git a/src/org/apache/http/message/BasicHeaderIterator.java b/src/org/apache/http/message/BasicHeaderIterator.java
new file mode 100644
index 0000000..32cd1c8
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderIterator.java
@@ -0,0 +1,180 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderIterator.java $
+ * $Revision: 581981 $
+ * $Date: 2007-10-04 11:26:26 -0700 (Thu, 04 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import java.util.NoSuchElementException;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+
+
+/**
+ * Basic implementation of a {@link HeaderIterator}.
+ *
+ * @version $Revision: 581981 $
+ */
+public class BasicHeaderIterator implements HeaderIterator {
+
+ /**
+ * An array of headers to iterate over.
+ * Not all elements of this array are necessarily part of the iteration.
+ * This array will never be modified by the iterator.
+ * Derived implementations are expected to adhere to this restriction.
+ */
+ protected final Header[] allHeaders;
+
+
+ /**
+ * The position of the next header in {@link #allHeaders allHeaders}.
+ * Negative if the iteration is over.
+ */
+ protected int currentIndex;
+
+
+ /**
+ * The header name to filter by.
+ * <code>null</code> to iterate over all headers in the array.
+ */
+ protected String headerName;
+
+
+
+ /**
+ * Creates a new header iterator.
+ *
+ * @param headers an array of headers over which to iterate
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for any
+ */
+ public BasicHeaderIterator(Header[] headers, String name) {
+ if (headers == null) {
+ throw new IllegalArgumentException
+ ("Header array must not be null.");
+ }
+
+ this.allHeaders = headers;
+ this.headerName = name;
+ this.currentIndex = findNext(-1);
+ }
+
+
+ /**
+ * Determines the index of the next header.
+ *
+ * @param from one less than the index to consider first,
+ * -1 to search for the first header
+ *
+ * @return the index of the next header that matches the filter name,
+ * or negative if there are no more headers
+ */
+ protected int findNext(int from) {
+ if (from < -1)
+ return -1;
+
+ final int to = this.allHeaders.length-1;
+ boolean found = false;
+ while (!found && (from < to)) {
+ from++;
+ found = filterHeader(from);
+ }
+ return found ? from : -1;
+ }
+
+
+ /**
+ * Checks whether a header is part of the iteration.
+ *
+ * @param index the index of the header to check
+ *
+ * @return <code>true</code> if the header should be part of the
+ * iteration, <code>false</code> to skip
+ */
+ protected boolean filterHeader(int index) {
+ return (this.headerName == null) ||
+ this.headerName.equalsIgnoreCase(this.allHeaders[index].getName());
+ }
+
+
+ // non-javadoc, see interface HeaderIterator
+ public boolean hasNext() {
+ return (this.currentIndex >= 0);
+ }
+
+
+ /**
+ * Obtains the next header from this iteration.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public Header nextHeader()
+ throws NoSuchElementException {
+
+ final int current = this.currentIndex;
+ if (current < 0) {
+ throw new NoSuchElementException("Iteration already finished.");
+ }
+
+ this.currentIndex = findNext(current);
+
+ return this.allHeaders[current];
+ }
+
+
+ /**
+ * Returns the next header.
+ * Same as {@link #nextHeader nextHeader}, but not type-safe.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public final Object next()
+ throws NoSuchElementException {
+ return nextHeader();
+ }
+
+
+ /**
+ * Removing headers is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public void remove()
+ throws UnsupportedOperationException {
+
+ throw new UnsupportedOperationException
+ ("Removing headers is not supported.");
+ }
+}
diff --git a/src/org/apache/http/message/BasicHeaderValueFormatter.java b/src/org/apache/http/message/BasicHeaderValueFormatter.java
new file mode 100644
index 0000000..b63bdf7
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderValueFormatter.java
@@ -0,0 +1,441 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderValueFormatter.java $
+ * $Revision: 574185 $
+ * $Date: 2007-09-10 02:19:47 -0700 (Mon, 10 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Basic implementation for formatting header value elements.
+ * Instances of this class are stateless and thread-safe.
+ * Derived classes are expected to maintain these properties.
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ * @author and others
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 574185 $
+ *
+ * @since 4.0
+ */
+public class BasicHeaderValueFormatter implements HeaderValueFormatter {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicHeaderValueFormatter} is not a singleton, there
+ * can be many instances of the class itself and of derived classes.
+ * The instance here provides non-customized, default behavior.
+ */
+ public final static
+ BasicHeaderValueFormatter DEFAULT = new BasicHeaderValueFormatter();
+
+
+ /**
+ * Special characters that can be used as separators in HTTP parameters.
+ * These special characters MUST be in a quoted string to be used within
+ * a parameter value .
+ */
+ public final static String SEPARATORS = " ;,:@()<>\\\"/[]?={}\t";
+
+
+ /**
+ * Unsafe special characters that must be escaped using the backslash
+ * character
+ */
+ public final static String UNSAFE_CHARS = "\"\\";
+
+
+
+ // public default constructor
+
+
+
+ /**
+ * Formats an array of header elements.
+ *
+ * @param elems the header elements to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted header elements
+ */
+ public final static
+ String formatElements(final HeaderElement[] elems,
+ final boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatElements(null, elems, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatElements(CharArrayBuffer buffer,
+ final HeaderElement[] elems,
+ final boolean quote) {
+ if (elems == null) {
+ throw new IllegalArgumentException
+ ("Header element array must not be null.");
+ }
+
+ int len = estimateElementsLen(elems);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ for (int i=0; i<elems.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ formatHeaderElement(buffer, elems[i], quote);
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of formatted header elements.
+ *
+ * @param elems the header elements to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateElementsLen(final HeaderElement[] elems) {
+ if ((elems == null) || (elems.length < 1))
+ return 0;
+
+ int result = (elems.length-1) * 2; // elements separated by ", "
+ for (int i=0; i<elems.length; i++) {
+ result += estimateHeaderElementLen(elems[i]);
+ }
+
+ return result;
+ }
+
+
+
+ /**
+ * Formats a header element.
+ *
+ * @param elem the header element to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted header element
+ */
+ public final static
+ String formatHeaderElement(final HeaderElement elem,
+ boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatHeaderElement(null, elem, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatHeaderElement(CharArrayBuffer buffer,
+ final HeaderElement elem,
+ final boolean quote) {
+ if (elem == null) {
+ throw new IllegalArgumentException
+ ("Header element must not be null.");
+ }
+
+ int len = estimateHeaderElementLen(elem);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ buffer.append(elem.getName());
+ final String value = elem.getValue();
+ if (value != null) {
+ buffer.append('=');
+ doFormatValue(buffer, value, quote);
+ }
+
+ final int parcnt = elem.getParameterCount();
+ if (parcnt > 0) {
+ for (int i=0; i<parcnt; i++) {
+ buffer.append("; ");
+ formatNameValuePair(buffer, elem.getParameter(i), quote);
+ }
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of a formatted header element.
+ *
+ * @param elem the header element to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateHeaderElementLen(final HeaderElement elem) {
+ if (elem == null)
+ return 0;
+
+ int result = elem.getName().length(); // name
+ final String value = elem.getValue();
+ if (value != null) {
+ // assume quotes, but no escaped characters
+ result += 3 + value.length(); // ="value"
+ }
+
+ final int parcnt = elem.getParameterCount();
+ if (parcnt > 0) {
+ for (int i=0; i<parcnt; i++) {
+ result += 2 + // ; <param>
+ estimateNameValuePairLen(elem.getParameter(i));
+ }
+ }
+
+ return result;
+ }
+
+
+
+
+ /**
+ * Formats a set of parameters.
+ *
+ * @param nvps the parameters to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted parameters
+ */
+ public final static
+ String formatParameters(final NameValuePair[] nvps,
+ final boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatParameters(null, nvps, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatParameters(CharArrayBuffer buffer,
+ NameValuePair[] nvps,
+ boolean quote) {
+ if (nvps == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+
+ int len = estimateParametersLen(nvps);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ for (int i = 0; i < nvps.length; i++) {
+ if (i > 0) {
+ buffer.append("; ");
+ }
+ formatNameValuePair(buffer, nvps[i], quote);
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of formatted parameters.
+ *
+ * @param nvps the parameters to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateParametersLen(final NameValuePair[] nvps) {
+ if ((nvps == null) || (nvps.length < 1))
+ return 0;
+
+ int result = (nvps.length-1) * 2; // "; " between the parameters
+ for (int i=0; i<nvps.length; i++) {
+ result += estimateNameValuePairLen(nvps[i]);
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Formats a name-value pair.
+ *
+ * @param nvp the name-value pair to format
+ * @param quote <code>true</code> to always format with a quoted value,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted name-value pair
+ */
+ public final static
+ String formatNameValuePair(final NameValuePair nvp,
+ final boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatNameValuePair(null, nvp, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatNameValuePair(CharArrayBuffer buffer,
+ final NameValuePair nvp,
+ final boolean quote) {
+ if (nvp == null) {
+ throw new IllegalArgumentException
+ ("NameValuePair must not be null.");
+ }
+
+ int len = estimateNameValuePairLen(nvp);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ buffer.append(nvp.getName());
+ final String value = nvp.getValue();
+ if (value != null) {
+ buffer.append('=');
+ doFormatValue(buffer, value, quote);
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of a formatted name-value pair.
+ *
+ * @param nvp the name-value pair to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateNameValuePairLen(final NameValuePair nvp) {
+ if (nvp == null)
+ return 0;
+
+ int result = nvp.getName().length(); // name
+ final String value = nvp.getValue();
+ if (value != null) {
+ // assume quotes, but no escaped characters
+ result += 3 + value.length(); // ="value"
+ }
+ return result;
+ }
+
+
+ /**
+ * Actually formats the value of a name-value pair.
+ * This does not include a leading = character.
+ * Called from {@link #formatNameValuePair formatNameValuePair}.
+ *
+ * @param buffer the buffer to append to, never <code>null</code>
+ * @param value the value to append, never <code>null</code>
+ * @param quote <code>true</code> to always format with quotes,
+ * <code>false</code> to use quotes only when necessary
+ */
+ protected void doFormatValue(final CharArrayBuffer buffer,
+ final String value,
+ boolean quote) {
+
+ if (!quote) {
+ for (int i = 0; (i < value.length()) && !quote; i++) {
+ quote = isSeparator(value.charAt(i));
+ }
+ }
+
+ if (quote) {
+ buffer.append('"');
+ }
+ for (int i = 0; i < value.length(); i++) {
+ char ch = value.charAt(i);
+ if (isUnsafe(ch)) {
+ buffer.append('\\');
+ }
+ buffer.append(ch);
+ }
+ if (quote) {
+ buffer.append('"');
+ }
+ }
+
+
+ /**
+ * Checks whether a character is a {@link #SEPARATORS separator}.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is a separator,
+ * <code>false</code> otherwise
+ */
+ protected boolean isSeparator(char ch) {
+ return SEPARATORS.indexOf(ch) >= 0;
+ }
+
+
+ /**
+ * Checks whether a character is {@link #UNSAFE_CHARS unsafe}.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is unsafe,
+ * <code>false</code> otherwise
+ */
+ protected boolean isUnsafe(char ch) {
+ return UNSAFE_CHARS.indexOf(ch) >= 0;
+ }
+
+
+} // class BasicHeaderValueFormatter
diff --git a/src/org/apache/http/message/BasicHeaderValueParser.java b/src/org/apache/http/message/BasicHeaderValueParser.java
new file mode 100644
index 0000000..5216196
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderValueParser.java
@@ -0,0 +1,420 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderValueParser.java $
+ * $Revision: 595670 $
+ * $Date: 2007-11-16 06:15:01 -0800 (Fri, 16 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.CharArrayBuffer;
+
+
+
+/**
+ * Basic implementation for parsing header values into elements.
+ * Instances of this class are stateless and thread-safe.
+ * Derived classes are expected to maintain these properties.
+ *
+ * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ * @author and others
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 595670 $
+ *
+ * @since 4.0
+ */
+public class BasicHeaderValueParser implements HeaderValueParser {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicHeaderValueParser} is not a singleton, there
+ * can be many instances of the class itself and of derived classes.
+ * The instance here provides non-customized, default behavior.
+ */
+ public final static
+ BasicHeaderValueParser DEFAULT = new BasicHeaderValueParser();
+
+ private final static char PARAM_DELIMITER = ';';
+ private final static char ELEM_DELIMITER = ',';
+ private final static char[] ALL_DELIMITERS = new char[] {
+ PARAM_DELIMITER,
+ ELEM_DELIMITER
+ };
+
+ // public default constructor
+
+
+ /**
+ * Parses elements with the given parser.
+ *
+ * @param value the header value to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return array holding the header elements, never <code>null</code>
+ */
+ public final static
+ HeaderElement[] parseElements(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseElements(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public HeaderElement[] parseElements(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ List elements = new ArrayList();
+ while (!cursor.atEnd()) {
+ HeaderElement element = parseHeaderElement(buffer, cursor);
+ if (!(element.getName().length() == 0 && element.getValue() == null)) {
+ elements.add(element);
+ }
+ }
+ return (HeaderElement[])
+ elements.toArray(new HeaderElement[elements.size()]);
+ }
+
+
+ /**
+ * Parses an element with the given parser.
+ *
+ * @param value the header element to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return the parsed header element
+ */
+ public final static
+ HeaderElement parseHeaderElement(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseHeaderElement(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public HeaderElement parseHeaderElement(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ NameValuePair nvp = parseNameValuePair(buffer, cursor);
+ NameValuePair[] params = null;
+ if (!cursor.atEnd()) {
+ char ch = buffer.charAt(cursor.getPos() - 1);
+ if (ch != ELEM_DELIMITER) {
+ params = parseParameters(buffer, cursor);
+ }
+ }
+ return createHeaderElement(nvp.getName(), nvp.getValue(), params);
+ }
+
+
+ /**
+ * Creates a header element.
+ * Called from {@link #parseHeaderElement}.
+ *
+ * @return a header element representing the argument
+ */
+ protected HeaderElement createHeaderElement(
+ final String name,
+ final String value,
+ final NameValuePair[] params) {
+ return new BasicHeaderElement(name, value, params);
+ }
+
+
+ /**
+ * Parses parameters with the given parser.
+ *
+ * @param value the parameter list to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return array holding the parameters, never <code>null</code>
+ */
+ public final static
+ NameValuePair[] parseParameters(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseParameters(buffer, cursor);
+ }
+
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public NameValuePair[] parseParameters(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ int pos = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ while (pos < indexTo) {
+ char ch = buffer.charAt(pos);
+ if (HTTP.isWhitespace(ch)) {
+ pos++;
+ } else {
+ break;
+ }
+ }
+ cursor.updatePos(pos);
+ if (cursor.atEnd()) {
+ return new NameValuePair[] {};
+ }
+
+ List params = new ArrayList();
+ while (!cursor.atEnd()) {
+ NameValuePair param = parseNameValuePair(buffer, cursor);
+ params.add(param);
+ char ch = buffer.charAt(cursor.getPos() - 1);
+ if (ch == ELEM_DELIMITER) {
+ break;
+ }
+ }
+
+ return (NameValuePair[])
+ params.toArray(new NameValuePair[params.size()]);
+ }
+
+ /**
+ * Parses a name-value-pair with the given parser.
+ *
+ * @param value the NVP to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return the parsed name-value pair
+ */
+ public final static
+ NameValuePair parseNameValuePair(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseNameValuePair(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+ return parseNameValuePair(buffer, cursor, ALL_DELIMITERS);
+ }
+
+ private static boolean isOneOf(final char ch, final char[] chs) {
+ if (chs != null) {
+ for (int i = 0; i < chs.length; i++) {
+ if (ch == chs[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
+ final ParserCursor cursor,
+ final char[] delimiters) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ boolean terminated = false;
+
+ int pos = cursor.getPos();
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ // Find name
+ String name = null;
+ while (pos < indexTo) {
+ char ch = buffer.charAt(pos);
+ if (ch == '=') {
+ break;
+ }
+ if (isOneOf(ch, delimiters)) {
+ terminated = true;
+ break;
+ }
+ pos++;
+ }
+
+ if (pos == indexTo) {
+ terminated = true;
+ name = buffer.substringTrimmed(indexFrom, indexTo);
+ } else {
+ name = buffer.substringTrimmed(indexFrom, pos);
+ pos++;
+ }
+
+ if (terminated) {
+ cursor.updatePos(pos);
+ return createNameValuePair(name, null);
+ }
+
+ // Find value
+ String value = null;
+ int i1 = pos;
+
+ boolean qouted = false;
+ boolean escaped = false;
+ while (pos < indexTo) {
+ char ch = buffer.charAt(pos);
+ if (ch == '"' && !escaped) {
+ qouted = !qouted;
+ }
+ if (!qouted && !escaped && isOneOf(ch, delimiters)) {
+ terminated = true;
+ break;
+ }
+ if (escaped) {
+ escaped = false;
+ } else {
+ escaped = qouted && ch == '\\';
+ }
+ pos++;
+ }
+
+ int i2 = pos;
+ // Trim leading white spaces
+ while (i1 < i2 && (HTTP.isWhitespace(buffer.charAt(i1)))) {
+ i1++;
+ }
+ // Trim trailing white spaces
+ while ((i2 > i1) && (HTTP.isWhitespace(buffer.charAt(i2 - 1)))) {
+ i2--;
+ }
+ // Strip away quotes if necessary
+ if (((i2 - i1) >= 2)
+ && (buffer.charAt(i1) == '"')
+ && (buffer.charAt(i2 - 1) == '"')) {
+ i1++;
+ i2--;
+ }
+ value = buffer.substring(i1, i2);
+ if (terminated) {
+ pos++;
+ }
+ cursor.updatePos(pos);
+ return createNameValuePair(name, value);
+ }
+
+ /**
+ * Creates a name-value pair.
+ * Called from {@link #parseNameValuePair}.
+ *
+ * @param name the name
+ * @param value the value, or <code>null</code>
+ *
+ * @return a name-value pair representing the arguments
+ */
+ protected NameValuePair createNameValuePair(final String name, final String value) {
+ return new BasicNameValuePair(name, value);
+ }
+
+}
+
diff --git a/src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java b/src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java
new file mode 100644
index 0000000..dbb70c8
--- /dev/null
+++ b/src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java
@@ -0,0 +1,81 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHttpEntityEnclosingRequest.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Basic implementation of a request with an entity that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpEntityEnclosingRequest
+ extends BasicHttpRequest implements HttpEntityEnclosingRequest {
+
+ private HttpEntity entity;
+
+ public BasicHttpEntityEnclosingRequest(final String method, final String uri) {
+ super(method, uri);
+ }
+
+ public BasicHttpEntityEnclosingRequest(final String method, final String uri,
+ final ProtocolVersion ver) {
+ this(new BasicRequestLine(method, uri, ver));
+ }
+
+ public BasicHttpEntityEnclosingRequest(final RequestLine requestline) {
+ super(requestline);
+ }
+
+ public HttpEntity getEntity() {
+ return this.entity;
+ }
+
+ public void setEntity(final HttpEntity entity) {
+ this.entity = entity;
+ }
+
+ public boolean expectContinue() {
+ Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
+ return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicHttpRequest.java b/src/org/apache/http/message/BasicHttpRequest.java
new file mode 100644
index 0000000..eedf8bc
--- /dev/null
+++ b/src/org/apache/http/message/BasicHttpRequest.java
@@ -0,0 +1,98 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHttpRequest.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HttpRequest;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.params.HttpProtocolParams;
+
+/**
+ * Basic implementation of an HTTP request that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpRequest extends AbstractHttpMessage implements HttpRequest {
+
+ private final RequestLine requestline;
+ private final String method;
+ private final String uri;
+
+ public BasicHttpRequest(final String method, final String uri) {
+ super();
+ if (method == null) {
+ throw new IllegalArgumentException("Method name may not be null");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Request URI may not be null");
+ }
+ this.method = method;
+ this.uri = uri;
+ this.requestline = null;
+ }
+
+ public BasicHttpRequest(final String method, final String uri, final ProtocolVersion ver) {
+ this(new BasicRequestLine(method, uri, ver));
+ }
+
+ public BasicHttpRequest(final RequestLine requestline) {
+ super();
+ if (requestline == null) {
+ throw new IllegalArgumentException("Request line may not be null");
+ }
+ this.requestline = requestline;
+ this.method = requestline.getMethod();
+ this.uri = requestline.getUri();
+ }
+
+ public ProtocolVersion getProtocolVersion() {
+ if (this.requestline != null) {
+ return this.requestline.getProtocolVersion();
+ } else {
+ return HttpProtocolParams.getVersion(getParams());
+ }
+ }
+
+ public RequestLine getRequestLine() {
+ if (this.requestline != null) {
+ return this.requestline;
+ } else {
+ ProtocolVersion ver = HttpProtocolParams.getVersion(getParams());
+ return new BasicRequestLine(this.method, this.uri, ver);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicHttpResponse.java b/src/org/apache/http/message/BasicHttpResponse.java
new file mode 100644
index 0000000..7da4bea
--- /dev/null
+++ b/src/org/apache/http/message/BasicHttpResponse.java
@@ -0,0 +1,204 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHttpResponse.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.Locale;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.ReasonPhraseCatalog;
+
+
+/**
+ * Basic implementation of an HTTP response that can be modified.
+ * This implementation makes sure that there always is a status line.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpResponse extends AbstractHttpMessage
+ implements HttpResponse {
+
+ private StatusLine statusline;
+ private HttpEntity entity;
+ private ReasonPhraseCatalog reasonCatalog;
+ private Locale locale;
+
+
+ /**
+ * Creates a new response.
+ * This is the constructor to which all others map.
+ *
+ * @param statusline the status line
+ * @param catalog the reason phrase catalog, or
+ * <code>null</code> to disable automatic
+ * reason phrase lookup
+ * @param locale the locale for looking up reason phrases, or
+ * <code>null</code> for the system locale
+ */
+ public BasicHttpResponse(final StatusLine statusline,
+ final ReasonPhraseCatalog catalog,
+ final Locale locale) {
+ super();
+ if (statusline == null) {
+ throw new IllegalArgumentException("Status line may not be null.");
+ }
+ this.statusline = statusline;
+ this.reasonCatalog = catalog;
+ this.locale = (locale != null) ? locale : Locale.getDefault();
+ }
+
+ /**
+ * Creates a response from a status line.
+ * The response will not have a reason phrase catalog and
+ * use the system default locale.
+ *
+ * @param statusline the status line
+ */
+ public BasicHttpResponse(final StatusLine statusline) {
+ this(statusline, null, null);
+ }
+
+ /**
+ * Creates a response from elements of a status line.
+ * The response will not have a reason phrase catalog and
+ * use the system default locale.
+ *
+ * @param ver the protocol version of the response
+ * @param code the status code of the response
+ * @param reason the reason phrase to the status code, or
+ * <code>null</code>
+ */
+ public BasicHttpResponse(final ProtocolVersion ver,
+ final int code,
+ final String reason) {
+ this(new BasicStatusLine(ver, code, reason), null, null);
+ }
+
+
+ // non-javadoc, see interface HttpMessage
+ public ProtocolVersion getProtocolVersion() {
+ return this.statusline.getProtocolVersion();
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public StatusLine getStatusLine() {
+ return this.statusline;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public HttpEntity getEntity() {
+ return this.entity;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusLine(final StatusLine statusline) {
+ if (statusline == null) {
+ throw new IllegalArgumentException("Status line may not be null");
+ }
+ this.statusline = statusline;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusLine(final ProtocolVersion ver, final int code) {
+ // arguments checked in BasicStatusLine constructor
+ this.statusline = new BasicStatusLine(ver, code, getReason(code));
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusLine(final ProtocolVersion ver, final int code,
+ final String reason) {
+ // arguments checked in BasicStatusLine constructor
+ this.statusline = new BasicStatusLine(ver, code, reason);
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusCode(int code) {
+ // argument checked in BasicStatusLine constructor
+ ProtocolVersion ver = this.statusline.getProtocolVersion();
+ this.statusline = new BasicStatusLine(ver, code, getReason(code));
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setReasonPhrase(String reason) {
+
+ if ((reason != null) && ((reason.indexOf('\n') >= 0) ||
+ (reason.indexOf('\r') >= 0))
+ ) {
+ throw new IllegalArgumentException("Line break in reason phrase.");
+ }
+ this.statusline = new BasicStatusLine(this.statusline.getProtocolVersion(),
+ this.statusline.getStatusCode(),
+ reason);
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setEntity(final HttpEntity entity) {
+ this.entity = entity;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setLocale(Locale loc) {
+ if (loc == null) {
+ throw new IllegalArgumentException("Locale may not be null.");
+ }
+ this.locale = loc;
+ final int code = this.statusline.getStatusCode();
+ this.statusline = new BasicStatusLine
+ (this.statusline.getProtocolVersion(), code, getReason(code));
+ }
+
+ /**
+ * Looks up a reason phrase.
+ * This method evaluates the currently set catalog and locale.
+ * It also handles a missing catalog.
+ *
+ * @param code the status code for which to look up the reason
+ *
+ * @return the reason phrase, or <code>null</code> if there is none
+ */
+ protected String getReason(int code) {
+ return (this.reasonCatalog == null) ?
+ null : this.reasonCatalog.getReason(code, this.locale);
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicLineFormatter.java b/src/org/apache/http/message/BasicLineFormatter.java
new file mode 100644
index 0000000..7c3bbc4
--- /dev/null
+++ b/src/org/apache/http/message/BasicLineFormatter.java
@@ -0,0 +1,346 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicLineFormatter.java $
+ * $Revision: 574185 $
+ * $Date: 2007-09-10 02:19:47 -0700 (Mon, 10 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.FormattedHeader;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Interface for formatting elements of the HEAD section of an HTTP message.
+ * This is the complement to {@link LineParser}.
+ * There are individual methods for formatting a request line, a
+ * status line, or a header line. The formatting does <i>not</i> include the
+ * trailing line break sequence CR-LF.
+ * The formatted lines are returned in memory, the formatter does not depend
+ * on any specific IO mechanism.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author and others
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 574185 $
+ *
+ * @since 4.0
+ */
+public class BasicLineFormatter implements LineFormatter {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicLineFormatter} is not a singleton, there can
+ * be many instances of the class itself and of derived classes.
+ * The instance here provides non-customized, default behavior.
+ */
+ public final static BasicLineFormatter DEFAULT = new BasicLineFormatter();
+
+
+
+ // public default constructor
+
+
+ /**
+ * Obtains a buffer for formatting.
+ *
+ * @param buffer a buffer already available, or <code>null</code>
+ *
+ * @return the cleared argument buffer if there is one, or
+ * a new empty buffer that can be used for formatting
+ */
+ protected CharArrayBuffer initBuffer(CharArrayBuffer buffer) {
+ if (buffer != null) {
+ buffer.clear();
+ } else {
+ buffer = new CharArrayBuffer(64);
+ }
+ return buffer;
+ }
+
+
+ /**
+ * Formats a protocol version.
+ *
+ * @param version the protocol version to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted protocol version
+ */
+ public final static
+ String formatProtocolVersion(final ProtocolVersion version,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.appendProtocolVersion(null, version).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer appendProtocolVersion(final CharArrayBuffer buffer,
+ final ProtocolVersion version) {
+ if (version == null) {
+ throw new IllegalArgumentException
+ ("Protocol version may not be null");
+ }
+
+ // can't use initBuffer, that would clear the argument!
+ CharArrayBuffer result = buffer;
+ final int len = estimateProtocolVersionLen(version);
+ if (result == null) {
+ result = new CharArrayBuffer(len);
+ } else {
+ result.ensureCapacity(len);
+ }
+
+ result.append(version.getProtocol());
+ result.append('/');
+ result.append(Integer.toString(version.getMajor()));
+ result.append('.');
+ result.append(Integer.toString(version.getMinor()));
+
+ return result;
+ }
+
+
+ /**
+ * Guesses the length of a formatted protocol version.
+ * Needed to guess the length of a formatted request or status line.
+ *
+ * @param version the protocol version to format, or <code>null</code>
+ *
+ * @return the estimated length of the formatted protocol version,
+ * in characters
+ */
+ protected int estimateProtocolVersionLen(final ProtocolVersion version) {
+ return version.getProtocol().length() + 4; // room for "HTTP/1.1"
+ }
+
+
+ /**
+ * Formats a request line.
+ *
+ * @param reqline the request line to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted request line
+ */
+ public final static String formatRequestLine(final RequestLine reqline,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.formatRequestLine(null, reqline).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer formatRequestLine(CharArrayBuffer buffer,
+ RequestLine reqline) {
+ if (reqline == null) {
+ throw new IllegalArgumentException
+ ("Request line may not be null");
+ }
+
+ CharArrayBuffer result = initBuffer(buffer);
+ doFormatRequestLine(result, reqline);
+
+ return result;
+ }
+
+
+ /**
+ * Actually formats a request line.
+ * Called from {@link #formatRequestLine}.
+ *
+ * @param buffer the empty buffer into which to format,
+ * never <code>null</code>
+ * @param reqline the request line to format, never <code>null</code>
+ */
+ protected void doFormatRequestLine(final CharArrayBuffer buffer,
+ final RequestLine reqline) {
+ final String method = reqline.getMethod();
+ final String uri = reqline.getUri();
+
+ // room for "GET /index.html HTTP/1.1"
+ int len = method.length() + 1 + uri.length() + 1 +
+ estimateProtocolVersionLen(reqline.getProtocolVersion());
+ buffer.ensureCapacity(len);
+
+ buffer.append(method);
+ buffer.append(' ');
+ buffer.append(uri);
+ buffer.append(' ');
+ appendProtocolVersion(buffer, reqline.getProtocolVersion());
+ }
+
+
+
+ /**
+ * Formats a status line.
+ *
+ * @param statline the status line to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted status line
+ */
+ public final static String formatStatusLine(final StatusLine statline,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.formatStatusLine(null, statline).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer formatStatusLine(final CharArrayBuffer buffer,
+ final StatusLine statline) {
+ if (statline == null) {
+ throw new IllegalArgumentException
+ ("Status line may not be null");
+ }
+
+ CharArrayBuffer result = initBuffer(buffer);
+ doFormatStatusLine(result, statline);
+
+ return result;
+ }
+
+
+ /**
+ * Actually formats a status line.
+ * Called from {@link #formatStatusLine}.
+ *
+ * @param buffer the empty buffer into which to format,
+ * never <code>null</code>
+ * @param statline the status line to format, never <code>null</code>
+ */
+ protected void doFormatStatusLine(final CharArrayBuffer buffer,
+ final StatusLine statline) {
+
+ int len = estimateProtocolVersionLen(statline.getProtocolVersion())
+ + 1 + 3 + 1; // room for "HTTP/1.1 200 "
+ final String reason = statline.getReasonPhrase();
+ if (reason != null) {
+ len += reason.length();
+ }
+ buffer.ensureCapacity(len);
+
+ appendProtocolVersion(buffer, statline.getProtocolVersion());
+ buffer.append(' ');
+ buffer.append(Integer.toString(statline.getStatusCode()));
+ buffer.append(' '); // keep whitespace even if reason phrase is empty
+ if (reason != null) {
+ buffer.append(reason);
+ }
+ }
+
+
+ /**
+ * Formats a header.
+ *
+ * @param header the header to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted header
+ */
+ public final static String formatHeader(final Header header,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.formatHeader(null, header).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer formatHeader(CharArrayBuffer buffer,
+ Header header) {
+ if (header == null) {
+ throw new IllegalArgumentException
+ ("Header may not be null");
+ }
+ CharArrayBuffer result = null;
+
+ if (header instanceof FormattedHeader) {
+ // If the header is backed by a buffer, re-use the buffer
+ result = ((FormattedHeader)header).getBuffer();
+ } else {
+ result = initBuffer(buffer);
+ doFormatHeader(result, header);
+ }
+ return result;
+
+ } // formatHeader
+
+
+ /**
+ * Actually formats a header.
+ * Called from {@link #formatHeader}.
+ *
+ * @param buffer the empty buffer into which to format,
+ * never <code>null</code>
+ * @param header the header to format, never <code>null</code>
+ */
+ protected void doFormatHeader(final CharArrayBuffer buffer,
+ final Header header) {
+ final String name = header.getName();
+ final String value = header.getValue();
+
+ int len = name.length() + 2;
+ if (value != null) {
+ len += value.length();
+ }
+ buffer.ensureCapacity(len);
+
+ buffer.append(name);
+ buffer.append(": ");
+ if (value != null) {
+ buffer.append(value);
+ }
+ }
+
+
+} // class BasicLineFormatter
diff --git a/src/org/apache/http/message/BasicLineParser.java b/src/org/apache/http/message/BasicLineParser.java
new file mode 100644
index 0000000..c5e9ddb
--- /dev/null
+++ b/src/org/apache/http/message/BasicLineParser.java
@@ -0,0 +1,504 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicLineParser.java $
+ * $Revision: 591798 $
+ * $Date: 2007-11-04 08:19:29 -0800 (Sun, 04 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ParseException;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Basic parser for lines in the head section of an HTTP message.
+ * There are individual methods for parsing a request line, a
+ * status line, or a header line.
+ * The lines to parse are passed in memory, the parser does not depend
+ * on any specific IO mechanism.
+ * Instances of this class are stateless and thread-safe.
+ * Derived classes MUST maintain these properties.
+ *
+ * <p>
+ * Note: This class was created by refactoring parsing code located in
+ * various other classes. The author tags from those other classes have
+ * been replicated here, although the association with the parsing code
+ * taken from there has not been traced.
+ * </p>
+ *
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ * @author and others
+ */
+public class BasicLineParser implements LineParser {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicLineParser} is not a singleton, there can
+ * be many instances of the class itself and of derived classes.
+ * The instance here provides non-customized, default behavior.
+ */
+ public final static BasicLineParser DEFAULT = new BasicLineParser();
+
+
+ /**
+ * A version of the protocol to parse.
+ * The version is typically not relevant, but the protocol name.
+ */
+ protected final ProtocolVersion protocol;
+
+
+ /**
+ * Creates a new line parser for the given HTTP-like protocol.
+ *
+ * @param proto a version of the protocol to parse, or
+ * <code>null</code> for HTTP. The actual version
+ * is not relevant, only the protocol name.
+ */
+ public BasicLineParser(ProtocolVersion proto) {
+ if (proto == null) {
+ proto = HttpVersion.HTTP_1_1;
+ }
+ this.protocol = proto;
+ }
+
+
+ /**
+ * Creates a new line parser for HTTP.
+ */
+ public BasicLineParser() {
+ this(null);
+ }
+
+
+
+ public final static
+ ProtocolVersion parseProtocolVersion(String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null.");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseProtocolVersion(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface LineParser
+ public ProtocolVersion parseProtocolVersion(final CharArrayBuffer buffer,
+ final ParserCursor cursor)
+ throws ParseException {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ final String protoname = this.protocol.getProtocol();
+ final int protolength = protoname.length();
+
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ skipWhitespace(buffer, cursor);
+
+ int i = cursor.getPos();
+
+ // long enough for "HTTP/1.1"?
+ if (i + protolength + 4 > indexTo) {
+ throw new ParseException
+ ("Not a valid protocol version: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ // check the protocol name and slash
+ boolean ok = true;
+ for (int j=0; ok && (j<protolength); j++) {
+ ok = (buffer.charAt(i+j) == protoname.charAt(j));
+ }
+ if (ok) {
+ ok = (buffer.charAt(i+protolength) == '/');
+ }
+ if (!ok) {
+ throw new ParseException
+ ("Not a valid protocol version: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ i += protolength+1;
+
+ int period = buffer.indexOf('.', i, indexTo);
+ if (period == -1) {
+ throw new ParseException
+ ("Invalid protocol version number: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ int major;
+ try {
+ major = Integer.parseInt(buffer.substringTrimmed(i, period));
+ } catch (NumberFormatException e) {
+ throw new ParseException
+ ("Invalid protocol major version number: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ i = period + 1;
+
+ int blank = buffer.indexOf(' ', i, indexTo);
+ if (blank == -1) {
+ blank = indexTo;
+ }
+ int minor;
+ try {
+ minor = Integer.parseInt(buffer.substringTrimmed(i, blank));
+ } catch (NumberFormatException e) {
+ throw new ParseException(
+ "Invalid protocol minor version number: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ cursor.updatePos(blank);
+
+ return createProtocolVersion(major, minor);
+
+ } // parseProtocolVersion
+
+
+ /**
+ * Creates a protocol version.
+ * Called from {@link #parseProtocolVersion}.
+ *
+ * @param major the major version number, for example 1 in HTTP/1.0
+ * @param minor the minor version number, for example 0 in HTTP/1.0
+ *
+ * @return the protocol version
+ */
+ protected ProtocolVersion createProtocolVersion(int major, int minor) {
+ return protocol.forVersion(major, minor);
+ }
+
+
+
+ // non-javadoc, see interface LineParser
+ public boolean hasProtocolVersion(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+ int index = cursor.getPos();
+
+ final String protoname = this.protocol.getProtocol();
+ final int protolength = protoname.length();
+
+ if (buffer.length() < protolength+4)
+ return false; // not long enough for "HTTP/1.1"
+
+ if (index < 0) {
+ // end of line, no tolerance for trailing whitespace
+ // this works only for single-digit major and minor version
+ index = buffer.length() -4 -protolength;
+ } else if (index == 0) {
+ // beginning of line, tolerate leading whitespace
+ while ((index < buffer.length()) &&
+ HTTP.isWhitespace(buffer.charAt(index))) {
+ index++;
+ }
+ } // else within line, don't tolerate whitespace
+
+
+ if (index + protolength + 4 > buffer.length())
+ return false;
+
+
+ // just check protocol name and slash, no need to analyse the version
+ boolean ok = true;
+ for (int j=0; ok && (j<protolength); j++) {
+ ok = (buffer.charAt(index+j) == protoname.charAt(j));
+ }
+ if (ok) {
+ ok = (buffer.charAt(index+protolength) == '/');
+ }
+
+ return ok;
+ }
+
+
+
+ public final static
+ RequestLine parseRequestLine(final String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null.");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseRequestLine(buffer, cursor);
+ }
+
+
+ /**
+ * Parses a request line.
+ *
+ * @param buffer a buffer holding the line to parse
+ *
+ * @return the parsed request line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ public RequestLine parseRequestLine(final CharArrayBuffer buffer,
+ final ParserCursor cursor)
+ throws ParseException {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ try {
+ skipWhitespace(buffer, cursor);
+ int i = cursor.getPos();
+
+ int blank = buffer.indexOf(' ', i, indexTo);
+ if (blank < 0) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ String method = buffer.substringTrimmed(i, blank);
+ cursor.updatePos(blank);
+
+ skipWhitespace(buffer, cursor);
+ i = cursor.getPos();
+
+ blank = buffer.indexOf(' ', i, indexTo);
+ if (blank < 0) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ String uri = buffer.substringTrimmed(i, blank);
+ cursor.updatePos(blank);
+
+ ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
+
+ skipWhitespace(buffer, cursor);
+ if (!cursor.atEnd()) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ return createRequestLine(method, uri, ver);
+ } catch (IndexOutOfBoundsException e) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ } // parseRequestLine
+
+
+ /**
+ * Instantiates a new request line.
+ * Called from {@link #parseRequestLine}.
+ *
+ * @param method the request method
+ * @param uri the requested URI
+ * @param ver the protocol version
+ *
+ * @return a new status line with the given data
+ */
+ protected RequestLine createRequestLine(final String method,
+ final String uri,
+ final ProtocolVersion ver) {
+ return new BasicRequestLine(method, uri, ver);
+ }
+
+
+
+ public final static
+ StatusLine parseStatusLine(final String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null.");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseStatusLine(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface LineParser
+ public StatusLine parseStatusLine(final CharArrayBuffer buffer,
+ final ParserCursor cursor)
+ throws ParseException {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ try {
+ // handle the HTTP-Version
+ ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
+
+ // handle the Status-Code
+ skipWhitespace(buffer, cursor);
+ int i = cursor.getPos();
+
+ int blank = buffer.indexOf(' ', i, indexTo);
+ if (blank < 0) {
+ blank = indexTo;
+ }
+ int statusCode = 0;
+ try {
+ statusCode =
+ Integer.parseInt(buffer.substringTrimmed(i, blank));
+ } catch (NumberFormatException e) {
+ throw new ParseException(
+ "Unable to parse status code from status line: "
+ + buffer.substring(indexFrom, indexTo));
+ }
+ //handle the Reason-Phrase
+ i = blank;
+ String reasonPhrase = null;
+ if (i < indexTo) {
+ reasonPhrase = buffer.substringTrimmed(i, indexTo);
+ } else {
+ reasonPhrase = "";
+ }
+ return createStatusLine(ver, statusCode, reasonPhrase);
+
+ } catch (IndexOutOfBoundsException e) {
+ throw new ParseException("Invalid status line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ } // parseStatusLine
+
+
+ /**
+ * Instantiates a new status line.
+ * Called from {@link #parseStatusLine}.
+ *
+ * @param ver the protocol version
+ * @param status the status code
+ * @param reason the reason phrase
+ *
+ * @return a new status line with the given data
+ */
+ protected StatusLine createStatusLine(final ProtocolVersion ver,
+ final int status,
+ final String reason) {
+ return new BasicStatusLine(ver, status, reason);
+ }
+
+
+
+ public final static
+ Header parseHeader(final String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ return parser.parseHeader(buffer);
+ }
+
+
+ // non-javadoc, see interface LineParser
+ public Header parseHeader(CharArrayBuffer buffer)
+ throws ParseException {
+
+ // the actual parser code is in the constructor of BufferedHeader
+ return new BufferedHeader(buffer);
+ }
+
+
+ /**
+ * Helper to skip whitespace.
+ */
+ protected void skipWhitespace(final CharArrayBuffer buffer, final ParserCursor cursor) {
+ int pos = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+ while ((pos < indexTo) &&
+ HTTP.isWhitespace(buffer.charAt(pos))) {
+ pos++;
+ }
+ cursor.updatePos(pos);
+ }
+
+} // class BasicLineParser
diff --git a/src/org/apache/http/message/BasicListHeaderIterator.java b/src/org/apache/http/message/BasicListHeaderIterator.java
new file mode 100644
index 0000000..69b8c06
--- /dev/null
+++ b/src/org/apache/http/message/BasicListHeaderIterator.java
@@ -0,0 +1,196 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicListHeaderIterator.java $
+ * $Revision: 584542 $
+ * $Date: 2007-10-14 06:29:34 -0700 (Sun, 14 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+
+
+/**
+ * Implementation of a {@link HeaderIterator} based on a {@link List}.
+ * For use by {@link HeaderGroup}.
+ *
+ * @version $Revision: 584542 $
+ */
+public class BasicListHeaderIterator implements HeaderIterator {
+
+ /**
+ * A list of headers to iterate over.
+ * Not all elements of this array are necessarily part of the iteration.
+ */
+ protected final List allHeaders;
+
+
+ /**
+ * The position of the next header in {@link #allHeaders allHeaders}.
+ * Negative if the iteration is over.
+ */
+ protected int currentIndex;
+
+
+ /**
+ * The position of the last returned header.
+ * Negative if none has been returned so far.
+ */
+ protected int lastIndex;
+
+
+ /**
+ * The header name to filter by.
+ * <code>null</code> to iterate over all headers in the array.
+ */
+ protected String headerName;
+
+
+
+ /**
+ * Creates a new header iterator.
+ *
+ * @param headers a list of headers over which to iterate
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for any
+ */
+ public BasicListHeaderIterator(List headers, String name) {
+ if (headers == null) {
+ throw new IllegalArgumentException
+ ("Header list must not be null.");
+ }
+
+ this.allHeaders = headers;
+ this.headerName = name;
+ this.currentIndex = findNext(-1);
+ this.lastIndex = -1;
+ }
+
+
+ /**
+ * Determines the index of the next header.
+ *
+ * @param from one less than the index to consider first,
+ * -1 to search for the first header
+ *
+ * @return the index of the next header that matches the filter name,
+ * or negative if there are no more headers
+ */
+ protected int findNext(int from) {
+ if (from < -1)
+ return -1;
+
+ final int to = this.allHeaders.size()-1;
+ boolean found = false;
+ while (!found && (from < to)) {
+ from++;
+ found = filterHeader(from);
+ }
+ return found ? from : -1;
+ }
+
+
+ /**
+ * Checks whether a header is part of the iteration.
+ *
+ * @param index the index of the header to check
+ *
+ * @return <code>true</code> if the header should be part of the
+ * iteration, <code>false</code> to skip
+ */
+ protected boolean filterHeader(int index) {
+ if (this.headerName == null)
+ return true;
+
+ // non-header elements, including null, will trigger exceptions
+ final String name = ((Header)this.allHeaders.get(index)).getName();
+
+ return this.headerName.equalsIgnoreCase(name);
+ }
+
+
+ // non-javadoc, see interface HeaderIterator
+ public boolean hasNext() {
+ return (this.currentIndex >= 0);
+ }
+
+
+ /**
+ * Obtains the next header from this iteration.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public Header nextHeader()
+ throws NoSuchElementException {
+
+ final int current = this.currentIndex;
+ if (current < 0) {
+ throw new NoSuchElementException("Iteration already finished.");
+ }
+
+ this.lastIndex = current;
+ this.currentIndex = findNext(current);
+
+ return (Header) this.allHeaders.get(current);
+ }
+
+
+ /**
+ * Returns the next header.
+ * Same as {@link #nextHeader nextHeader}, but not type-safe.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public final Object next()
+ throws NoSuchElementException {
+ return nextHeader();
+ }
+
+
+ /**
+ * Removes the header that was returned last.
+ */
+ public void remove()
+ throws UnsupportedOperationException {
+
+ if (this.lastIndex < 0) {
+ throw new IllegalStateException("No header to remove.");
+ }
+ this.allHeaders.remove(this.lastIndex);
+ this.lastIndex = -1;
+ this.currentIndex--; // adjust for the removed element
+ }
+}
diff --git a/src/org/apache/http/message/BasicNameValuePair.java b/src/org/apache/http/message/BasicNameValuePair.java
new file mode 100644
index 0000000..59fcb42
--- /dev/null
+++ b/src/org/apache/http/message/BasicNameValuePair.java
@@ -0,0 +1,189 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicNameValuePair.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.LangUtils;
+
+/**
+ * A simple class encapsulating an attribute/value pair.
+ * <p>
+ * This class comforms to the generic grammar and formatting rules outlined in the
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2">Section 2.2</a>
+ * and
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>
+ * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
+ * </p>
+ * <h>2.2 Basic Rules</h>
+ * <p>
+ * The following rules are used throughout this specification to describe basic parsing constructs.
+ * The US-ASCII coded character set is defined by ANSI X3.4-1986.
+ * </p>
+ * <pre>
+ * OCTET = <any 8-bit sequence of data>
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ * LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ * ALPHA = UPALPHA | LOALPHA
+ * DIGIT = <any US-ASCII digit "0".."9">
+ * CTL = <any US-ASCII control character
+ * (octets 0 - 31) and DEL (127)>
+ * CR = <US-ASCII CR, carriage return (13)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * <"> = <US-ASCII double-quote mark (34)>
+ * </pre>
+ * <p>
+ * Many HTTP/1.1 header field values consist of words separated by LWS or special
+ * characters. These special characters MUST be in a quoted string to be used within
+ * a parameter value (as defined in section 3.6).
+ * <p>
+ * <pre>
+ * token = 1*<any CHAR except CTLs or separators>
+ * separators = "(" | ")" | "<" | ">" | "@"
+ * | "," | ";" | ":" | "\" | <">
+ * | "/" | "[" | "]" | "?" | "="
+ * | "{" | "}" | SP | HT
+ * </pre>
+ * <p>
+ * A string of text is parsed as a single word if it is quoted using double-quote marks.
+ * </p>
+ * <pre>
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext = <any TEXT except <">>
+ * </pre>
+ * <p>
+ * The backslash character ("\") MAY be used as a single-character quoting mechanism only
+ * within quoted-string and comment constructs.
+ * </p>
+ * <pre>
+ * quoted-pair = "\" CHAR
+ * </pre>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ *
+ */
+public class BasicNameValuePair implements NameValuePair, Cloneable {
+
+ private final String name;
+ private final String value;
+
+ /**
+ * Default Constructor taking a name and a value. The value may be null.
+ *
+ * @param name The name.
+ * @param value The value.
+ */
+ public BasicNameValuePair(final String name, final String value) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns the name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+
+ /**
+ * Get a string representation of this pair.
+ *
+ * @return A string representation.
+ */
+ public String toString() {
+ // don't call complex default formatting for a simple toString
+
+ int len = this.name.length();
+ if (this.value != null)
+ len += 1 + this.value.length();
+ CharArrayBuffer buffer = new CharArrayBuffer(len);
+
+ buffer.append(this.name);
+ if (this.value != null) {
+ buffer.append("=");
+ buffer.append(this.value);
+ }
+ return buffer.toString();
+ }
+
+ public boolean equals(final Object object) {
+ if (object == null) return false;
+ if (this == object) return true;
+ if (object instanceof NameValuePair) {
+ BasicNameValuePair that = (BasicNameValuePair) object;
+ return this.name.equals(that.name)
+ && LangUtils.equals(this.value, that.value);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.name);
+ hash = LangUtils.hashCode(hash, this.value);
+ return hash;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicRequestLine.java b/src/org/apache/http/message/BasicRequestLine.java
new file mode 100644
index 0000000..b826064
--- /dev/null
+++ b/src/org/apache/http/message/BasicRequestLine.java
@@ -0,0 +1,99 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicRequestLine.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+
+/**
+ * The first line of an {@link org.apache.http.HttpRequest HttpRequest}.
+ * It contains the method, URI, and HTTP version of the request.
+ * For details, see RFC 2616.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 604625 $
+ *
+ * @since 4.0
+ */
+public class BasicRequestLine implements RequestLine, Cloneable {
+
+ private final ProtocolVersion protoversion;
+ private final String method;
+ private final String uri;
+
+ public BasicRequestLine(final String method,
+ final String uri,
+ final ProtocolVersion version) {
+ super();
+ if (method == null) {
+ throw new IllegalArgumentException
+ ("Method must not be null.");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException
+ ("URI must not be null.");
+ }
+ if (version == null) {
+ throw new IllegalArgumentException
+ ("Protocol version must not be null.");
+ }
+ this.method = method;
+ this.uri = uri;
+ this.protoversion = version;
+ }
+
+ public String getMethod() {
+ return this.method;
+ }
+
+ public ProtocolVersion getProtocolVersion() {
+ return this.protoversion;
+ }
+
+ public String getUri() {
+ return this.uri;
+ }
+
+ public String toString() {
+ // no need for non-default formatting in toString()
+ return BasicLineFormatter.DEFAULT
+ .formatRequestLine(null, this).toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicStatusLine.java b/src/org/apache/http/message/BasicStatusLine.java
new file mode 100644
index 0000000..c34cefe
--- /dev/null
+++ b/src/org/apache/http/message/BasicStatusLine.java
@@ -0,0 +1,124 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicStatusLine.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+
+
+
+/**
+ * Represents a status line as returned from a HTTP server.
+ * See <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a> section 6.1.
+ * This class is immutable and therefore inherently thread safe.
+ *
+ * @see HttpStatus
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @version $Id: BasicStatusLine.java 604625 2007-12-16 14:11:11Z olegk $
+ *
+ * @since 4.0
+ */
+public class BasicStatusLine implements StatusLine, Cloneable {
+
+ // ----------------------------------------------------- Instance Variables
+
+ /** The protocol version. */
+ private final ProtocolVersion protoVersion;
+
+ /** The status code. */
+ private final int statusCode;
+
+ /** The reason phrase. */
+ private final String reasonPhrase;
+
+ // ----------------------------------------------------------- Constructors
+ /**
+ * Creates a new status line with the given version, status, and reason.
+ *
+ * @param version the protocol version of the response
+ * @param statusCode the status code of the response
+ * @param reasonPhrase the reason phrase to the status code, or
+ * <code>null</code>
+ */
+ public BasicStatusLine(final ProtocolVersion version, int statusCode,
+ final String reasonPhrase) {
+ super();
+ if (version == null) {
+ throw new IllegalArgumentException
+ ("Protocol version may not be null.");
+ }
+ if (statusCode < 0) {
+ throw new IllegalArgumentException
+ ("Status code may not be negative.");
+ }
+ this.protoVersion = version;
+ this.statusCode = statusCode;
+ this.reasonPhrase = reasonPhrase;
+ }
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * @return the Status-Code
+ */
+ public int getStatusCode() {
+ return this.statusCode;
+ }
+
+ /**
+ * @return the HTTP-Version
+ */
+ public ProtocolVersion getProtocolVersion() {
+ return this.protoVersion;
+ }
+
+ /**
+ * @return the Reason-Phrase
+ */
+ public String getReasonPhrase() {
+ return this.reasonPhrase;
+ }
+
+ public String toString() {
+ // no need for non-default formatting in toString()
+ return BasicLineFormatter.DEFAULT
+ .formatStatusLine(null, this).toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicTokenIterator.java b/src/org/apache/http/message/BasicTokenIterator.java
new file mode 100644
index 0000000..5fbf5ba
--- /dev/null
+++ b/src/org/apache/http/message/BasicTokenIterator.java
@@ -0,0 +1,429 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicTokenIterator.java $
+ * $Revision: 602520 $
+ * $Date: 2007-12-08 09:42:26 -0800 (Sat, 08 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.NoSuchElementException;
+
+import org.apache.http.HeaderIterator;
+import org.apache.http.ParseException;
+import org.apache.http.TokenIterator;
+
+/**
+ * Basic implementation of a {@link TokenIterator}.
+ * This implementation parses <tt>#token<tt> sequences as
+ * defined by RFC 2616, section 2.
+ * It extends that definition somewhat beyond US-ASCII.
+ *
+ * @version $Revision: 602520 $
+ */
+public class BasicTokenIterator implements TokenIterator {
+
+ /** The HTTP separator characters. Defined in RFC 2616, section 2.2. */
+ // the order of the characters here is adjusted to put the
+ // most likely candidates at the beginning of the collection
+ public final static String HTTP_SEPARATORS = " ,;=()<>@:\\\"/[]?{}\t";
+
+
+ /** The iterator from which to obtain the next header. */
+ protected final HeaderIterator headerIt;
+
+ /**
+ * The value of the current header.
+ * This is the header value that includes {@link #currentToken}.
+ * Undefined if the iteration is over.
+ */
+ protected String currentHeader;
+
+ /**
+ * The token to be returned by the next call to {@link #currentToken}.
+ * <code>null</code> if the iteration is over.
+ */
+ protected String currentToken;
+
+ /**
+ * The position after {@link #currentToken} in {@link #currentHeader}.
+ * Undefined if the iteration is over.
+ */
+ protected int searchPos;
+
+
+ /**
+ * Creates a new instance of {@link BasicTokenIterator}.
+ *
+ * @param headerIterator the iterator for the headers to tokenize
+ */
+ public BasicTokenIterator(final HeaderIterator headerIterator) {
+ if (headerIterator == null) {
+ throw new IllegalArgumentException
+ ("Header iterator must not be null.");
+ }
+
+ this.headerIt = headerIterator;
+ this.searchPos = findNext(-1);
+ }
+
+
+ // non-javadoc, see interface TokenIterator
+ public boolean hasNext() {
+ return (this.currentToken != null);
+ }
+
+
+ /**
+ * Obtains the next token from this iteration.
+ *
+ * @return the next token in this iteration
+ *
+ * @throws NoSuchElementException if the iteration is already over
+ * @throws ParseException if an invalid header value is encountered
+ */
+ public String nextToken()
+ throws NoSuchElementException, ParseException {
+
+ if (this.currentToken == null) {
+ throw new NoSuchElementException("Iteration already finished.");
+ }
+
+ final String result = this.currentToken;
+ // updates currentToken, may trigger ParseException:
+ this.searchPos = findNext(this.searchPos);
+
+ return result;
+ }
+
+
+ /**
+ * Returns the next token.
+ * Same as {@link #nextToken}, but with generic return type.
+ *
+ * @return the next token in this iteration
+ *
+ * @throws NoSuchElementException if there are no more tokens
+ * @throws ParseException if an invalid header value is encountered
+ */
+ public final Object next()
+ throws NoSuchElementException, ParseException {
+ return nextToken();
+ }
+
+
+ /**
+ * Removing tokens is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final void remove()
+ throws UnsupportedOperationException {
+
+ throw new UnsupportedOperationException
+ ("Removing tokens is not supported.");
+ }
+
+
+ /**
+ * Determines the next token.
+ * If found, the token is stored in {@link #currentToken}.
+ * The return value indicates the position after the token
+ * in {@link #currentHeader}. If necessary, the next header
+ * will be obtained from {@link #headerIt}.
+ * If not found, {@link #currentToken} is set to <code>null</code>.
+ *
+ * @param from the position in the current header at which to
+ * start the search, -1 to search in the first header
+ *
+ * @return the position after the found token in the current header, or
+ * negative if there was no next token
+ *
+ * @throws ParseException if an invalid header value is encountered
+ */
+ protected int findNext(int from)
+ throws ParseException {
+
+ if (from < 0) {
+ // called from the constructor, initialize the first header
+ if (!this.headerIt.hasNext()) {
+ return -1;
+ }
+ this.currentHeader = this.headerIt.nextHeader().getValue();
+ from = 0;
+ } else {
+ // called after a token, make sure there is a separator
+ from = findTokenSeparator(from);
+ }
+
+ int start = findTokenStart(from);
+ if (start < 0) {
+ this.currentToken = null;
+ return -1; // nothing found
+ }
+
+ int end = findTokenEnd(start);
+ this.currentToken = createToken(this.currentHeader, start, end);
+ return end;
+ }
+
+
+ /**
+ * Creates a new token to be returned.
+ * Called from {@link #findNext findNext} after the token is identified.
+ * The default implementation simply calls
+ * {@link java.lang.String#substring String.substring}.
+ * <br/>
+ * If header values are significantly longer than tokens, and some
+ * tokens are permanently referenced by the application, there can
+ * be problems with garbage collection. A substring will hold a
+ * reference to the full characters of the original string and
+ * therefore occupies more memory than might be expected.
+ * To avoid this, override this method and create a new string
+ * instead of a substring.
+ *
+ * @param value the full header value from which to create a token
+ * @param start the index of the first token character
+ * @param end the index after the last token character
+ *
+ * @return a string representing the token identified by the arguments
+ */
+ protected String createToken(String value, int start, int end) {
+ return value.substring(start, end);
+ }
+
+
+ /**
+ * Determines the starting position of the next token.
+ * This method will iterate over headers if necessary.
+ *
+ * @param from the position in the current header at which to
+ * start the search
+ *
+ * @return the position of the token start in the current header,
+ * negative if no token start could be found
+ */
+ protected int findTokenStart(int from) {
+ if (from < 0) {
+ throw new IllegalArgumentException
+ ("Search position must not be negative: " + from);
+ }
+
+ boolean found = false;
+ while (!found && (this.currentHeader != null)) {
+
+ final int to = this.currentHeader.length();
+ while (!found && (from < to)) {
+
+ final char ch = this.currentHeader.charAt(from);
+ if (isTokenSeparator(ch) || isWhitespace(ch)) {
+ // whitspace and token separators are skipped
+ from++;
+ } else if (isTokenChar(this.currentHeader.charAt(from))) {
+ // found the start of a token
+ found = true;
+ } else {
+ throw new ParseException
+ ("Invalid character before token (pos " + from +
+ "): " + this.currentHeader);
+ }
+ }
+ if (!found) {
+ if (this.headerIt.hasNext()) {
+ this.currentHeader = this.headerIt.nextHeader().getValue();
+ from = 0;
+ } else {
+ this.currentHeader = null;
+ }
+ }
+ } // while headers
+
+ return found ? from : -1;
+ }
+
+
+ /**
+ * Determines the position of the next token separator.
+ * Because of multi-header joining rules, the end of a
+ * header value is a token separator. This method does
+ * therefore not need to iterate over headers.
+ *
+ * @param from the position in the current header at which to
+ * start the search
+ *
+ * @return the position of a token separator in the current header,
+ * or at the end
+ *
+ * @throws ParseException
+ * if a new token is found before a token separator.
+ * RFC 2616, section 2.1 explicitly requires a comma between
+ * tokens for <tt>#</tt>.
+ */
+ protected int findTokenSeparator(int from) {
+ if (from < 0) {
+ throw new IllegalArgumentException
+ ("Search position must not be negative: " + from);
+ }
+
+ boolean found = false;
+ final int to = this.currentHeader.length();
+ while (!found && (from < to)) {
+ final char ch = this.currentHeader.charAt(from);
+ if (isTokenSeparator(ch)) {
+ found = true;
+ } else if (isWhitespace(ch)) {
+ from++;
+ } else if (isTokenChar(ch)) {
+ throw new ParseException
+ ("Tokens without separator (pos " + from +
+ "): " + this.currentHeader);
+ } else {
+ throw new ParseException
+ ("Invalid character after token (pos " + from +
+ "): " + this.currentHeader);
+ }
+ }
+
+ return from;
+ }
+
+
+ /**
+ * Determines the ending position of the current token.
+ * This method will not leave the current header value,
+ * since the end of the header value is a token boundary.
+ *
+ * @param from the position of the first character of the token
+ *
+ * @return the position after the last character of the token.
+ * The behavior is undefined if <code>from</code> does not
+ * point to a token character in the current header value.
+ */
+ protected int findTokenEnd(int from) {
+ if (from < 0) {
+ throw new IllegalArgumentException
+ ("Token start position must not be negative: " + from);
+ }
+
+ final int to = this.currentHeader.length();
+ int end = from+1;
+ while ((end < to) && isTokenChar(this.currentHeader.charAt(end))) {
+ end++;
+ }
+
+ return end;
+ }
+
+
+ /**
+ * Checks whether a character is a token separator.
+ * RFC 2616, section 2.1 defines comma as the separator for
+ * <tt>#token</tt> sequences. The end of a header value will
+ * also separate tokens, but that is not a character check.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is a token separator,
+ * <code>false</code> otherwise
+ */
+ protected boolean isTokenSeparator(char ch) {
+ return (ch == ',');
+ }
+
+
+ /**
+ * Checks whether a character is a whitespace character.
+ * RFC 2616, section 2.2 defines space and horizontal tab as whitespace.
+ * The optional preceeding line break is irrelevant, since header
+ * continuation is handled transparently when parsing messages.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is whitespace,
+ * <code>false</code> otherwise
+ */
+ protected boolean isWhitespace(char ch) {
+
+ // we do not use Character.isWhitspace(ch) here, since that allows
+ // many control characters which are not whitespace as per RFC 2616
+ return ((ch == '\t') || Character.isSpaceChar(ch));
+ }
+
+
+ /**
+ * Checks whether a character is a valid token character.
+ * Whitespace, control characters, and HTTP separators are not
+ * valid token characters. The HTTP specification (RFC 2616, section 2.2)
+ * defines tokens only for the US-ASCII character set, this
+ * method extends the definition to other character sets.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is a valid token start,
+ * <code>false</code> otherwise
+ */
+ protected boolean isTokenChar(char ch) {
+
+ // common sense extension of ALPHA + DIGIT
+ if (Character.isLetterOrDigit(ch))
+ return true;
+
+ // common sense extension of CTL
+ if (Character.isISOControl(ch))
+ return false;
+
+ // no common sense extension for this
+ if (isHttpSeparator(ch))
+ return false;
+
+ // RFC 2616, section 2.2 defines a token character as
+ // "any CHAR except CTLs or separators". The controls
+ // and separators are included in the checks above.
+ // This will yield unexpected results for Unicode format characters.
+ // If that is a problem, overwrite isHttpSeparator(char) to filter
+ // out the false positives.
+ return true;
+ }
+
+
+ /**
+ * Checks whether a character is an HTTP separator.
+ * The implementation in this class checks only for the HTTP separators
+ * defined in RFC 2616, section 2.2. If you need to detect other
+ * separators beyond the US-ASCII character set, override this method.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is an HTTP separator
+ */
+ protected boolean isHttpSeparator(char ch) {
+ return (HTTP_SEPARATORS.indexOf(ch) >= 0);
+ }
+
+
+} // class BasicTokenIterator
+
diff --git a/src/org/apache/http/message/BufferedHeader.java b/src/org/apache/http/message/BufferedHeader.java
new file mode 100644
index 0000000..35c5cfc
--- /dev/null
+++ b/src/org/apache/http/message/BufferedHeader.java
@@ -0,0 +1,133 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BufferedHeader.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.HeaderElement;
+import org.apache.http.ParseException;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * This class represents a raw HTTP header whose content is parsed 'on demand'
+ * only when the header value needs to be consumed.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 604625 $ $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ */
+public class BufferedHeader implements FormattedHeader, Cloneable {
+
+ /**
+ * Header name.
+ */
+ private final String name;
+
+ /**
+ * The buffer containing the entire header line.
+ */
+ private final CharArrayBuffer buffer;
+
+ /**
+ * The beginning of the header value in the buffer
+ */
+ private final int valuePos;
+
+
+ /**
+ * Creates a new header from a buffer.
+ * The name of the header will be parsed immediately,
+ * the value only if it is accessed.
+ *
+ * @param buffer the buffer containing the header to represent
+ *
+ * @throws ParseException in case of a parse error
+ */
+ public BufferedHeader(final CharArrayBuffer buffer)
+ throws ParseException {
+
+ super();
+ if (buffer == null) {
+ throw new IllegalArgumentException
+ ("Char array buffer may not be null");
+ }
+ int colon = buffer.indexOf(':');
+ if (colon == -1) {
+ throw new ParseException
+ ("Invalid header: " + buffer.toString());
+ }
+ String s = buffer.substringTrimmed(0, colon);
+ if (s.length() == 0) {
+ throw new ParseException
+ ("Invalid header: " + buffer.toString());
+ }
+ this.buffer = buffer;
+ this.name = s;
+ this.valuePos = colon + 1;
+ }
+
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getValue() {
+ return this.buffer.substringTrimmed(this.valuePos, this.buffer.length());
+ }
+
+ public HeaderElement[] getElements() throws ParseException {
+ ParserCursor cursor = new ParserCursor(0, this.buffer.length());
+ cursor.updatePos(this.valuePos);
+ return BasicHeaderValueParser.DEFAULT
+ .parseElements(this.buffer, cursor);
+ }
+
+ public int getValuePos() {
+ return this.valuePos;
+ }
+
+ public CharArrayBuffer getBuffer() {
+ return this.buffer;
+ }
+
+ public String toString() {
+ return this.buffer.toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ // buffer is considered immutable
+ // no need to make a copy of it
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/HeaderGroup.java b/src/org/apache/http/message/HeaderGroup.java
new file mode 100644
index 0000000..4e40db1
--- /dev/null
+++ b/src/org/apache/http/message/HeaderGroup.java
@@ -0,0 +1,295 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/HeaderGroup.java $
+ * $Revision: 659185 $
+ * $Date: 2008-05-22 11:07:36 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * A class for combining a set of headers.
+ * This class allows for multiple headers with the same name and
+ * keeps track of the order in which headers were added.
+ *
+ * @author Michael Becke
+ *
+ * @since 4.0
+ */
+public class HeaderGroup implements Cloneable {
+
+ /** The list of headers for this group, in the order in which they were added */
+ private List headers;
+
+ /**
+ * Constructor for HeaderGroup.
+ */
+ public HeaderGroup() {
+ this.headers = new ArrayList(16);
+ }
+
+ /**
+ * Removes any contained headers.
+ */
+ public void clear() {
+ headers.clear();
+ }
+
+ /**
+ * Adds the given header to the group. The order in which this header was
+ * added is preserved.
+ *
+ * @param header the header to add
+ */
+ public void addHeader(Header header) {
+ if (header == null) {
+ return;
+ }
+ headers.add(header);
+ }
+
+ /**
+ * Removes the given header.
+ *
+ * @param header the header to remove
+ */
+ public void removeHeader(Header header) {
+ if (header == null) {
+ return;
+ }
+ headers.remove(header);
+ }
+
+ /**
+ * Replaces the first occurence of the header with the same name. If no header with
+ * the same name is found the given header is added to the end of the list.
+ *
+ * @param header the new header that should replace the first header with the same
+ * name if present in the list.
+ */
+ public void updateHeader(Header header) {
+ if (header == null) {
+ return;
+ }
+ for (int i = 0; i < this.headers.size(); i++) {
+ Header current = (Header) this.headers.get(i);
+ if (current.getName().equalsIgnoreCase(header.getName())) {
+ this.headers.set(i, header);
+ return;
+ }
+ }
+ this.headers.add(header);
+ }
+
+ /**
+ * Sets all of the headers contained within this group overriding any
+ * existing headers. The headers are added in the order in which they appear
+ * in the array.
+ *
+ * @param headers the headers to set
+ */
+ public void setHeaders(Header[] headers) {
+ clear();
+ if (headers == null) {
+ return;
+ }
+ for (int i = 0; i < headers.length; i++) {
+ this.headers.add(headers[i]);
+ }
+ }
+
+ /**
+ * Gets a header representing all of the header values with the given name.
+ * If more that one header with the given name exists the values will be
+ * combined with a "," as per RFC 2616.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header(s) to get
+ * @return a header with a condensed value or <code>null</code> if no
+ * headers by the given name are present
+ */
+ public Header getCondensedHeader(String name) {
+ Header[] headers = getHeaders(name);
+
+ if (headers.length == 0) {
+ return null;
+ } else if (headers.length == 1) {
+ return headers[0];
+ } else {
+ CharArrayBuffer valueBuffer = new CharArrayBuffer(128);
+ valueBuffer.append(headers[0].getValue());
+ for (int i = 1; i < headers.length; i++) {
+ valueBuffer.append(", ");
+ valueBuffer.append(headers[i].getValue());
+ }
+
+ return new BasicHeader(name.toLowerCase(Locale.ENGLISH), valueBuffer.toString());
+ }
+ }
+
+ /**
+ * Gets all of the headers with the given name. The returned array
+ * maintains the relative order in which the headers were added.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header(s) to get
+ *
+ * @return an array of length >= 0
+ */
+ public Header[] getHeaders(String name) {
+ ArrayList headersFound = new ArrayList();
+
+ for (int i = 0; i < headers.size(); i++) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ headersFound.add(header);
+ }
+ }
+
+ return (Header[]) headersFound.toArray(new Header[headersFound.size()]);
+ }
+
+ /**
+ * Gets the first header with the given name.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header to get
+ * @return the first header or <code>null</code>
+ */
+ public Header getFirstHeader(String name) {
+ for (int i = 0; i < headers.size(); i++) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ return header;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the last header with the given name.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header to get
+ * @return the last header or <code>null</code>
+ */
+ public Header getLastHeader(String name) {
+ // start at the end of the list and work backwards
+ for (int i = headers.size() - 1; i >= 0; i--) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ return header;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets all of the headers contained within this group.
+ *
+ * @return an array of length >= 0
+ */
+ public Header[] getAllHeaders() {
+ return (Header[]) headers.toArray(new Header[headers.size()]);
+ }
+
+ /**
+ * Tests if headers with the given name are contained within this group.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the header name to test for
+ * @return <code>true</code> if at least one header with the name is
+ * contained, <code>false</code> otherwise
+ */
+ public boolean containsHeader(String name) {
+ for (int i = 0; i < headers.size(); i++) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an iterator over this group of headers.
+ *
+ * @return iterator over this group of headers.
+ *
+ * @since 4.0
+ */
+ public HeaderIterator iterator() {
+ return new BasicListHeaderIterator(this.headers, null);
+ }
+
+ /**
+ * Returns an iterator over the headers with a given name in this group.
+ *
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for all headers
+ *
+ * @return iterator over some headers in this group.
+ *
+ * @since 4.0
+ */
+ public HeaderIterator iterator(final String name) {
+ return new BasicListHeaderIterator(this.headers, name);
+ }
+
+ /**
+ * Returns a copy of this object
+ *
+ * @return copy of this object
+ */
+ public HeaderGroup copy() {
+ HeaderGroup clone = new HeaderGroup();
+ clone.headers.addAll(this.headers);
+ return clone;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ HeaderGroup clone = (HeaderGroup) super.clone();
+ clone.headers = new ArrayList(this.headers);
+ return clone;
+ }
+
+}
diff --git a/src/org/apache/http/message/HeaderValueFormatter.java b/src/org/apache/http/message/HeaderValueFormatter.java
new file mode 100644
index 0000000..4f6351f
--- /dev/null
+++ b/src/org/apache/http/message/HeaderValueFormatter.java
@@ -0,0 +1,141 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/HeaderValueFormatter.java $
+ * $Revision: 571954 $
+ * $Date: 2007-09-02 04:05:21 -0700 (Sun, 02 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+
+
+
+/**
+ * Interface for formatting elements of a header value.
+ * This is the complement to {@link HeaderValueParser}.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * <p>
+ * All formatting methods accept an optional buffer argument.
+ * If a buffer is passed in, the formatted element will be appended
+ * and the modified buffer is returned. If no buffer is passed in,
+ * a new buffer will be created and filled with the formatted element.
+ * In both cases, the caller is allowed to modify the returned buffer.
+ * </p>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 571954 $
+ *
+ * @since 4.0
+ */
+public interface HeaderValueFormatter {
+
+ /**
+ * Formats an array of header elements.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param elems the header elements to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted header elements.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatElements(CharArrayBuffer buffer,
+ HeaderElement[] elems,
+ boolean quote)
+ ;
+
+
+ /**
+ * Formats one header element.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param elem the header element to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted header element.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatHeaderElement(CharArrayBuffer buffer,
+ HeaderElement elem,
+ boolean quote)
+ ;
+
+
+
+ /**
+ * Formats the parameters of a header element.
+ * That's a list of name-value pairs, to be separated by semicolons.
+ * This method will <i>not</i> generate a leading semicolon.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param nvps the parameters (name-value pairs) to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted parameters.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatParameters(CharArrayBuffer buffer,
+ NameValuePair[] nvps,
+ boolean quote)
+ ;
+
+
+ /**
+ * Formats one name-value pair, where the value is optional.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param nvp the name-value pair to format
+ * @param quote <code>true</code> to always format with a quoted value,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted name-value pair.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatNameValuePair(CharArrayBuffer buffer,
+ NameValuePair nvp,
+ boolean quote)
+ ;
+
+}
+
diff --git a/src/org/apache/http/message/HeaderValueParser.java b/src/org/apache/http/message/HeaderValueParser.java
new file mode 100644
index 0000000..74bb93c
--- /dev/null
+++ b/src/org/apache/http/message/HeaderValueParser.java
@@ -0,0 +1,214 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/HeaderValueParser.java $
+ * $Revision: 589325 $
+ * $Date: 2007-10-28 03:37:56 -0700 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.util.CharArrayBuffer;
+
+
+
+/**
+ * Interface for parsing header values into elements.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 589325 $ $Date: 2007-10-28 03:37:56 -0700 (Sun, 28 Oct 2007) $
+ *
+ * @since 4.0
+ */
+public interface HeaderValueParser {
+
+ /**
+ * Parses a header value into elements.
+ * Parse errors are indicated as <code>RuntimeException</code>.
+ * <p>
+ * Some HTTP headers (such as the set-cookie header) have values that
+ * can be decomposed into multiple elements. In order to be processed
+ * by this parser, such headers must be in the following form:
+ * </p>
+ * <pre>
+ * header = [ element ] *( "," [ element ] )
+ * element = name [ "=" [ value ] ] *( ";" [ param ] )
+ * param = name [ "=" [ value ] ]
+ *
+ * name = token
+ * value = ( token | quoted-string )
+ *
+ * token = 1*&lt;any char except "=", ",", ";", &lt;"&gt; and
+ * white space&gt;
+ * quoted-string = &lt;"&gt; *( text | quoted-char ) &lt;"&gt;
+ * text = any char except &lt;"&gt;
+ * quoted-char = "\" char
+ * </pre>
+ * <p>
+ * Any amount of white space is allowed between any part of the
+ * header, element or param and is ignored. A missing value in any
+ * element or param will be stored as the empty {@link String};
+ * if the "=" is also missing <var>null</var> will be stored instead.
+ * </p>
+ *
+ * @param buffer buffer holding the header value to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return an array holding all elements of the header value
+ *
+ * @throws ParseException in case of a parse error
+ */
+ HeaderElement[] parseElements(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+ /**
+ * Parses a single header element.
+ * A header element consist of a semicolon-separate list
+ * of name=value definitions.
+ *
+ * @param buffer buffer holding the element to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed element
+ *
+ * @throws ParseException in case of a parse error
+ */
+ HeaderElement parseHeaderElement(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+ /**
+ * Parses a list of name-value pairs.
+ * These lists are used to specify parameters to a header element.
+ * Parse errors are indicated as <code>RuntimeException</code>.
+ * <p>
+ * This method comforms to the generic grammar and formatting rules
+ * outlined in the
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2"
+ * >Section 2.2</a>
+ * and
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6"
+ * >Section 3.6</a>
+ * of
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>.
+ * </p>
+ * <h>2.2 Basic Rules</h>
+ * <p>
+ * The following rules are used throughout this specification to
+ * describe basic parsing constructs.
+ * The US-ASCII coded character set is defined by ANSI X3.4-1986.
+ * </p>
+ * <pre>
+ * OCTET = <any 8-bit sequence of data>
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ * LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ * ALPHA = UPALPHA | LOALPHA
+ * DIGIT = <any US-ASCII digit "0".."9">
+ * CTL = <any US-ASCII control character
+ * (octets 0 - 31) and DEL (127)>
+ * CR = <US-ASCII CR, carriage return (13)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * <"> = <US-ASCII double-quote mark (34)>
+ * </pre>
+ * <p>
+ * Many HTTP/1.1 header field values consist of words separated
+ * by LWS or special characters. These special characters MUST be
+ * in a quoted string to be used within
+ * a parameter value (as defined in section 3.6).
+ * <p>
+ * <pre>
+ * token = 1*<any CHAR except CTLs or separators>
+ * separators = "(" | ")" | "<" | ">" | "@"
+ * | "," | ";" | ":" | "\" | <">
+ * | "/" | "[" | "]" | "?" | "="
+ * | "{" | "}" | SP | HT
+ * </pre>
+ * <p>
+ * A string of text is parsed as a single word if it is quoted using
+ * double-quote marks.
+ * </p>
+ * <pre>
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext = <any TEXT except <">>
+ * </pre>
+ * <p>
+ * The backslash character ("\") MAY be used as a single-character
+ * quoting mechanism only within quoted-string and comment constructs.
+ * </p>
+ * <pre>
+ * quoted-pair = "\" CHAR
+ * </pre>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ *
+ * @param buffer buffer holding the name-value list to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return an array holding all items of the name-value list
+ *
+ * @throws ParseException in case of a parse error
+ */
+ NameValuePair[] parseParameters(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Parses a name=value specification, where the = and value are optional.
+ *
+ * @param buffer the buffer holding the name-value pair to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the name-value pair, where the value is <code>null</code>
+ * if no value is specified
+ */
+ NameValuePair parseNameValuePair(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+}
+
diff --git a/src/org/apache/http/message/LineFormatter.java b/src/org/apache/http/message/LineFormatter.java
new file mode 100644
index 0000000..ccc603c
--- /dev/null
+++ b/src/org/apache/http/message/LineFormatter.java
@@ -0,0 +1,153 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/LineFormatter.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Interface for formatting elements of the HEAD section of an HTTP message.
+ * This is the complement to {@link LineParser}.
+ * There are individual methods for formatting a request line, a
+ * status line, or a header line. The formatting does <i>not</i> include the
+ * trailing line break sequence CR-LF.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * <p>
+ * The formatted lines are returned in memory, the formatter does not depend
+ * on any specific IO mechanism.
+ * In order to avoid unnecessary creation of temporary objects,
+ * a buffer can be passed as argument to all formatting methods.
+ * The implementation may or may not actually use that buffer for formatting.
+ * If it is used, the buffer will first be cleared by the
+ * <code>formatXXX</code> methods.
+ * The argument buffer can always be re-used after the call. The buffer
+ * returned as the result, if it is different from the argument buffer,
+ * MUST NOT be modified.
+ * </p>
+ *
+ *
+ * @author <a href="mailto:rolandw AT apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 573864 $ $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * @since 4.0
+ */
+public interface LineFormatter {
+
+
+
+ /**
+ * Formats a protocol version.
+ * This method does <i>not</i> follow the general contract for
+ * <code>buffer</code> arguments.
+ * It does <i>not</i> clear the argument buffer, but appends instead.
+ * The returned buffer can always be modified by the caller.
+ * Because of these differing conventions, it is not named
+ * <code>formatProtocolVersion</code>.
+ *
+ * @param buffer a buffer to which to append, or <code>null</code>
+ * @param version the protocol version to format
+ *
+ * @return a buffer with the formatted protocol version appended.
+ * The caller is allowed to modify the result buffer.
+ * If the <code>buffer</code> argument is not <code>null</code>,
+ * the returned buffer is the argument buffer.
+ */
+ CharArrayBuffer appendProtocolVersion(CharArrayBuffer buffer,
+ ProtocolVersion version)
+ ;
+
+
+ /**
+ * Formats a request line.
+ *
+ * @param buffer a buffer available for formatting, or
+ * <code>null</code>.
+ * The buffer will be cleared before use.
+ * @param reqline the request line to format
+ *
+ * @return the formatted request line
+ */
+ CharArrayBuffer formatRequestLine(CharArrayBuffer buffer,
+ RequestLine reqline)
+ ;
+
+
+ /**
+ * Formats a status line.
+ *
+ * @param buffer a buffer available for formatting, or
+ * <code>null</code>.
+ * The buffer will be cleared before use.
+ * @param statline the status line to format
+ *
+ * @return the formatted status line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ CharArrayBuffer formatStatusLine(CharArrayBuffer buffer,
+ StatusLine statline)
+ ;
+
+
+ /**
+ * Formats a header.
+ * Due to header continuation, the result may be multiple lines.
+ * In order to generate well-formed HTTP, the lines in the result
+ * must be separated by the HTTP line break sequence CR-LF.
+ * There is <i>no</i> trailing CR-LF in the result.
+ * <br/>
+ * See the class comment for details about the buffer argument.
+ *
+ * @param buffer a buffer available for formatting, or
+ * <code>null</code>.
+ * The buffer will be cleared before use.
+ * @param header the header to format
+ *
+ * @return a buffer holding the formatted header, never <code>null</code>.
+ * The returned buffer may be different from the argument buffer.
+ *
+ * @throws ParseException in case of a parse error
+ */
+ CharArrayBuffer formatHeader(CharArrayBuffer buffer,
+ Header header)
+ ;
+
+}
diff --git a/src/org/apache/http/message/LineParser.java b/src/org/apache/http/message/LineParser.java
new file mode 100644
index 0000000..d1bcd15
--- /dev/null
+++ b/src/org/apache/http/message/LineParser.java
@@ -0,0 +1,156 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/LineParser.java $
+ * $Revision: 589374 $
+ * $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ParseException;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Interface for parsing lines in the HEAD section of an HTTP message.
+ * There are individual methods for parsing a request line, a
+ * status line, or a header line.
+ * The lines to parse are passed in memory, the parser does not depend
+ * on any specific IO mechanism.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * @author <a href="mailto:rolandw AT apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 589374 $ $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $
+ *
+ * @since 4.0
+ */
+public interface LineParser {
+
+
+ /**
+ * Parses the textual representation of a protocol version.
+ * This is needed for parsing request lines (last element)
+ * as well as status lines (first element).
+ *
+ * @param buffer a buffer holding the protocol version to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed protocol version
+ *
+ * @throws ParseException in case of a parse error
+ */
+ ProtocolVersion parseProtocolVersion(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Checks whether there likely is a protocol version in a line.
+ * This method implements a <i>heuristic</i> to check for a
+ * likely protocol version specification. It does <i>not</i>
+ * guarantee that {@link #parseProtocolVersion} would not
+ * detect a parse error.
+ * This can be used to detect garbage lines before a request
+ * or status line.
+ *
+ * @param buffer a buffer holding the line to inspect
+ * @param cursor the cursor at which to check for a protocol version, or
+ * negative for "end of line". Whether the check tolerates
+ * whitespace before or after the protocol version is
+ * implementation dependent.
+ *
+ * @return <code>true</code> if there is a protocol version at the
+ * argument index (possibly ignoring whitespace),
+ * <code>false</code> otherwise
+ */
+ boolean hasProtocolVersion(
+ CharArrayBuffer buffer,
+ ParserCursor cursor);
+
+
+ /**
+ * Parses a request line.
+ *
+ * @param buffer a buffer holding the line to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed request line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ RequestLine parseRequestLine(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Parses a status line.
+ *
+ * @param buffer a buffer holding the line to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed status line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ StatusLine parseStatusLine(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Creates a header from a line.
+ * The full header line is expected here. Header continuation lines
+ * must be joined by the caller before invoking this method.
+ *
+ * @param buffer a buffer holding the full header line.
+ * This buffer MUST NOT be re-used afterwards, since
+ * the returned object may reference the contents later.
+ *
+ * @return the header in the argument buffer.
+ * The returned object MAY be a wrapper for the argument buffer.
+ * The argument buffer MUST NOT be re-used or changed afterwards.
+ *
+ * @throws ParseException in case of a parse error
+ */
+ Header parseHeader(CharArrayBuffer buffer)
+ throws ParseException
+ ;
+
+
+}
diff --git a/src/org/apache/http/message/ParserCursor.java b/src/org/apache/http/message/ParserCursor.java
new file mode 100644
index 0000000..d030675
--- /dev/null
+++ b/src/org/apache/http/message/ParserCursor.java
@@ -0,0 +1,102 @@
+/*
+ * $HeadURL:https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/ParserCursor.java $
+ * $Revision:589325 $
+ * $Date:2007-10-28 11:37:56 +0100 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * This class represents a context of a parsing operation:
+ * <ul>
+ * <li>the current position the parsing operation is expected to start at</li>
+ * <li>the bounds limiting the scope of the parsing operation</li>
+ * </ul>
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ */
+public class ParserCursor {
+
+ private final int lowerBound;
+ private final int upperBound;
+ private int pos;
+
+ public ParserCursor(int lowerBound, int upperBound) {
+ super();
+ if (lowerBound < 0) {
+ throw new IndexOutOfBoundsException("Lower bound cannot be negative");
+ }
+ if (lowerBound > upperBound) {
+ throw new IndexOutOfBoundsException("Lower bound cannot be greater then upper bound");
+ }
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ this.pos = lowerBound;
+ }
+
+ public int getLowerBound() {
+ return this.lowerBound;
+ }
+
+ public int getUpperBound() {
+ return this.upperBound;
+ }
+
+ public int getPos() {
+ return this.pos;
+ }
+
+ public void updatePos(int pos) {
+ if (pos < this.lowerBound) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (pos > this.upperBound) {
+ throw new IndexOutOfBoundsException();
+ }
+ this.pos = pos;
+ }
+
+ public boolean atEnd() {
+ return this.pos >= this.upperBound;
+ }
+
+ public String toString() {
+ CharArrayBuffer buffer = new CharArrayBuffer(16);
+ buffer.append('[');
+ buffer.append(Integer.toString(this.lowerBound));
+ buffer.append('>');
+ buffer.append(Integer.toString(this.pos));
+ buffer.append('>');
+ buffer.append(Integer.toString(this.upperBound));
+ buffer.append(']');
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/message/package.html b/src/org/apache/http/message/package.html
new file mode 100644
index 0000000..88ee617
--- /dev/null
+++ b/src/org/apache/http/message/package.html
@@ -0,0 +1,49 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/package.html $
+ * $Revision: 539755 $
+ * $Date: 2007-05-19 07:05:02 -0700 (Sat, 19 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+A selection of HTTP
+{@link org.apache.http.message.AbstractHttpMessage message}
+implementations.
+
+There are basic implementations for HTTP requests
+{@link org.apache.http.message.BasicHttpEntityEnclosingRequest with}
+and {@link org.apache.http.message.BasicHttpRequest without}
+an entity, and for
+{@link org.apache.http.message.BasicHttpResponse responses}.
+
+
+</body>
+</html>
diff --git a/src/org/apache/http/package.html b/src/org/apache/http/package.html
new file mode 100644
index 0000000..e9647b4
--- /dev/null
+++ b/src/org/apache/http/package.html
@@ -0,0 +1,51 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/package.html $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The core interfaces and classes of the HTTP components.
+
+These deal with the fundamental things required for using the
+HTTP protocol, such as representing a
+{@link org.apache.http.HttpMessage message} including it's
+{@link org.apache.http.Header headers} and optional
+{@link org.apache.http.HttpEntity entity}, and
+{@link org.apache.http.HttpConnection connections}
+over which messages are sent. In order to prepare messages
+before sending or after receiving, there are interceptors for
+{@link org.apache.http.HttpRequestInterceptor requests} and
+{@link org.apache.http.HttpResponseInterceptor responses}.
+
+</body>
+</html>
diff --git a/src/org/apache/http/params/AbstractHttpParams.java b/src/org/apache/http/params/AbstractHttpParams.java
new file mode 100644
index 0000000..91631fc
--- /dev/null
+++ b/src/org/apache/http/params/AbstractHttpParams.java
@@ -0,0 +1,116 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/AbstractHttpParams.java $
+ * $Revision: 542224 $
+ * $Date: 2007-05-28 06:34:04 -0700 (Mon, 28 May 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+import org.apache.http.params.HttpParams;
+
+
+/**
+ * Abstract base class for parameter collections.
+ * Type specific setters and getters are mapped to the abstract,
+ * generic getters and setters.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 542224 $
+ */
+public abstract class AbstractHttpParams implements HttpParams {
+
+ /**
+ * Instantiates parameters.
+ */
+ protected AbstractHttpParams() {
+ super();
+ }
+
+ public long getLongParameter(final String name, long defaultValue) {
+ Object param = getParameter(name);
+ if (param == null) {
+ return defaultValue;
+ }
+ return ((Long)param).longValue();
+ }
+
+ public HttpParams setLongParameter(final String name, long value) {
+ setParameter(name, new Long(value));
+ return this;
+ }
+
+ public int getIntParameter(final String name, int defaultValue) {
+ Object param = getParameter(name);
+ if (param == null) {
+ return defaultValue;
+ }
+ return ((Integer)param).intValue();
+ }
+
+ public HttpParams setIntParameter(final String name, int value) {
+ setParameter(name, new Integer(value));
+ return this;
+ }
+
+ public double getDoubleParameter(final String name, double defaultValue) {
+ Object param = getParameter(name);
+ if (param == null) {
+ return defaultValue;
+ }
+ return ((Double)param).doubleValue();
+ }
+
+ public HttpParams setDoubleParameter(final String name, double value) {
+ setParameter(name, new Double(value));
+ return this;
+ }
+
+ public boolean getBooleanParameter(final String name, boolean defaultValue) {
+ Object param = getParameter(name);
+ if (param == null) {
+ return defaultValue;
+ }
+ return ((Boolean)param).booleanValue();
+ }
+
+ public HttpParams setBooleanParameter(final String name, boolean value) {
+ setParameter(name, value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+ public boolean isParameterTrue(final String name) {
+ return getBooleanParameter(name, false);
+ }
+
+ public boolean isParameterFalse(final String name) {
+ return !getBooleanParameter(name, false);
+ }
+
+} // class AbstractHttpParams
diff --git a/src/org/apache/http/params/BasicHttpParams.java b/src/org/apache/http/params/BasicHttpParams.java
new file mode 100644
index 0000000..70e6605
--- /dev/null
+++ b/src/org/apache/http/params/BasicHttpParams.java
@@ -0,0 +1,160 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/BasicHttpParams.java $
+ * $Revision: 610464 $
+ * $Date: 2008-01-09 09:10:55 -0800 (Wed, 09 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ * This class represents a collection of HTTP protocol parameters.
+ * Protocol parameters may be linked together to form a hierarchy.
+ * If a particular parameter value has not been explicitly defined
+ * in the collection itself, its value will be drawn from the parent
+ * collection of parameters.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 610464 $
+ */
+public final class BasicHttpParams extends AbstractHttpParams
+ implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = -7086398485908701455L;
+
+ /** Map of HTTP parameters that this collection contains. */
+ private HashMap parameters;
+
+ public BasicHttpParams() {
+ super();
+ }
+
+ public Object getParameter(final String name) {
+ // See if the parameter has been explicitly defined
+ Object param = null;
+ if (this.parameters != null) {
+ param = this.parameters.get(name);
+ }
+ return param;
+ }
+
+ public HttpParams setParameter(final String name, final Object value) {
+ if (this.parameters == null) {
+ this.parameters = new HashMap();
+ }
+ this.parameters.put(name, value);
+ return this;
+ }
+
+ public boolean removeParameter(String name) {
+ if (this.parameters == null) {
+ return false;
+ }
+ //this is to avoid the case in which the key has a null value
+ if (this.parameters.containsKey(name)) {
+ this.parameters.remove(name);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Assigns the value to all the parameter with the given names
+ *
+ * @param names array of parameter name
+ * @param value parameter value
+ */
+ public void setParameters(final String[] names, final Object value) {
+ for (int i = 0; i < names.length; i++) {
+ setParameter(names[i], value);
+ }
+ }
+
+ public boolean isParameterSet(final String name) {
+ return getParameter(name) != null;
+ }
+
+ public boolean isParameterSetLocally(final String name) {
+ return this.parameters != null && this.parameters.get(name) != null;
+ }
+
+ /**
+ * Removes all parameters from this collection.
+ */
+ public void clear() {
+ this.parameters = null;
+ }
+
+ /**
+ * Creates a copy of these parameters.
+ * The implementation here instantiates {@link BasicHttpParams},
+ * then calls {@link #copyParams(HttpParams)} to populate the copy.
+ *
+ * @return a new set of params holding a copy of the
+ * <i>local</i> parameters in this object.
+ */
+ public HttpParams copy() {
+ BasicHttpParams clone = new BasicHttpParams();
+ copyParams(clone);
+ return clone;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ BasicHttpParams clone = (BasicHttpParams) super.clone();
+ copyParams(clone);
+ return clone;
+ }
+
+ /**
+ * Copies the locally defined parameters to the argument parameters.
+ * This method is called from {@link #copy()}.
+ *
+ * @param target the parameters to which to copy
+ */
+ protected void copyParams(HttpParams target) {
+ if (this.parameters == null)
+ return;
+
+ Iterator iter = parameters.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry me = (Map.Entry) iter.next();
+ if (me.getKey() instanceof String)
+ target.setParameter((String)me.getKey(), me.getValue());
+ }
+ }
+
+}
diff --git a/src/org/apache/http/params/CoreConnectionPNames.java b/src/org/apache/http/params/CoreConnectionPNames.java
new file mode 100644
index 0000000..a2dec8b
--- /dev/null
+++ b/src/org/apache/http/params/CoreConnectionPNames.java
@@ -0,0 +1,131 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/CoreConnectionPNames.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+
+/**
+ * Defines parameter names for connections in HttpCore.
+ *
+ * @version $Revision: 576077 $
+ *
+ * @since 4.0
+ */
+public interface CoreConnectionPNames {
+
+ /**
+ * Defines the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
+ * timeout for waiting for data. A timeout value of zero is interpreted as an infinite
+ * timeout. This value is used when no socket timeout is set in the
+ * method parameters.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ * @see java.net.SocketOptions#SO_TIMEOUT
+ */
+ public static final String SO_TIMEOUT = "http.socket.timeout";
+
+ /**
+ * Determines whether Nagle's algorithm is to be used. The Nagle's algorithm
+ * tries to conserve bandwidth by minimizing the number of segments that are
+ * sent. When applications wish to decrease network latency and increase
+ * performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY).
+ * Data will be sent earlier, at the cost of an increase in bandwidth consumption.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ * @see java.net.SocketOptions#TCP_NODELAY
+ */
+ public static final String TCP_NODELAY = "http.tcp.nodelay";
+
+ /**
+ * Determines the size of the internal socket buffer used to buffer data
+ * while receiving / transmitting HTTP messages.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String SOCKET_BUFFER_SIZE = "http.socket.buffer-size";
+
+ /**
+ * Sets SO_LINGER with the specified linger time in seconds. The maximum timeout
+ * value is platform specific. Value <tt>0</tt> implies that the option is disabled.
+ * Value <tt>-1</tt> implies that the JRE default is used. The setting only affects
+ * socket close.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ * @see java.net.SocketOptions#SO_LINGER
+ */
+ public static final String SO_LINGER = "http.socket.linger";
+
+ /**
+ * Determines the timeout until a connection is etablished. A value of zero
+ * means the timeout is not used. The default value is zero.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String CONNECTION_TIMEOUT = "http.connection.timeout";
+
+ /**
+ * Determines whether stale connection check is to be used. Disabling
+ * stale connection check may result in slight performance improvement
+ * at the risk of getting an I/O error when executing a request over a
+ * connection that has been closed at the server side.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String STALE_CONNECTION_CHECK = "http.connection.stalecheck";
+
+ /**
+ * Determines the maximum line length limit. If set to a positive value, any HTTP
+ * line exceeding this limit will cause an IOException. A negative or zero value
+ * will effectively disable the check.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String MAX_LINE_LENGTH = "http.connection.max-line-length";
+
+ /**
+ * Determines the maximum HTTP header count allowed. If set to a positive value,
+ * the number of HTTP headers received from the data stream exceeding this limit
+ * will cause an IOException. A negative or zero value will effectively disable
+ * the check.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String MAX_HEADER_COUNT = "http.connection.max-header-count";
+
+}
diff --git a/src/org/apache/http/params/CoreProtocolPNames.java b/src/org/apache/http/params/CoreProtocolPNames.java
new file mode 100644
index 0000000..a42c5de
--- /dev/null
+++ b/src/org/apache/http/params/CoreProtocolPNames.java
@@ -0,0 +1,132 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/CoreProtocolPNames.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+
+/**
+ * Defines parameter names for protocol execution in HttpCore.
+ *
+ * @version $Revision: 576077 $
+ *
+ * @since 4.0
+ */
+public interface CoreProtocolPNames {
+
+ /**
+ * Defines the {@link org.apache.http.ProtocolVersion protocol version}
+ * used per default.
+ * <p>
+ * This parameter expects a value of type
+ * {@link org.apache.http.ProtocolVersion}.
+ * </p>
+ */
+ public static final String PROTOCOL_VERSION = "http.protocol.version";
+
+ /**
+ * Defines the charset to be used for encoding HTTP protocol elements.
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * </p>
+ */
+ public static final String HTTP_ELEMENT_CHARSET = "http.protocol.element-charset";
+
+ /**
+ * Defines the charset to be used per default for encoding content body.
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * </p>
+ */
+ public static final String HTTP_CONTENT_CHARSET = "http.protocol.content-charset";
+
+ /**
+ * Defines the content of the <tt>User-Agent</tt> header.
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * </p>
+ */
+ public static final String USER_AGENT = "http.useragent";
+
+ /**
+ * Defines the content of the <tt>Server</tt> header.
+ * <p>
+ * This parameter expects a value of type {@link String}.
+ * </p>
+ */
+ public static final String ORIGIN_SERVER = "http.origin-server";
+
+ /**
+ * Defines whether responses with an invalid <tt>Transfer-Encoding</tt> header should be
+ * rejected.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String STRICT_TRANSFER_ENCODING = "http.protocol.strict-transfer-encoding";
+
+ /**
+ * <p>
+ * Activates 'Expect: 100-Continue' handshake for the
+ * entity enclosing methods. The purpose of the 'Expect: 100-Continue'
+ * handshake to allow a client that is sending a request message with
+ * a request body to determine if the origin server is willing to
+ * accept the request (based on the request headers) before the client
+ * sends the request body.
+ * </p>
+ *
+ * <p>
+ * The use of the 'Expect: 100-continue' handshake can result in
+ * noticable peformance improvement for entity enclosing requests
+ * (such as POST and PUT) that require the target server's
+ * authentication.
+ * </p>
+ *
+ * <p>
+ * 'Expect: 100-continue' handshake should be used with
+ * caution, as it may cause problems with HTTP servers and
+ * proxies that do not support HTTP/1.1 protocol.
+ * </p>
+ *
+ * This parameter expects a value of type {@link Boolean}.
+ */
+ public static final String USE_EXPECT_CONTINUE = "http.protocol.expect-continue";
+
+ /**
+ * <p>
+ * Defines the maximum period of time in milliseconds the client should spend
+ * waiting for a 100-continue response.
+ * </p>
+ *
+ * This parameter expects a value of type {@link Integer}.
+ */
+ public static final String WAIT_FOR_CONTINUE = "http.protocol.wait-for-continue";
+
+}
diff --git a/src/org/apache/http/params/DefaultedHttpParams.java b/src/org/apache/http/params/DefaultedHttpParams.java
new file mode 100644
index 0000000..ce33247
--- /dev/null
+++ b/src/org/apache/http/params/DefaultedHttpParams.java
@@ -0,0 +1,101 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/DefaultedHttpParams.java $
+ * $Revision: 610763 $
+ * $Date: 2008-01-10 04:01:13 -0800 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+import org.apache.http.params.HttpParams;
+
+/**
+ * {@link HttpParams} implementation that delegates resolution of a parameter
+ * to the given default {@link HttpParams} instance if the parameter is not
+ * present in the local one. The state of the local collection can be mutated,
+ * whereas the default collection is treated as read-only.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 610763 $
+ */
+public final class DefaultedHttpParams extends AbstractHttpParams {
+
+ private final HttpParams local;
+ private final HttpParams defaults;
+
+ public DefaultedHttpParams(final HttpParams local, final HttpParams defaults) {
+ super();
+ if (local == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.local = local;
+ this.defaults = defaults;
+ }
+
+ /**
+ * Creates a copy of the local collection with the same default
+ */
+ public HttpParams copy() {
+ HttpParams clone = this.local.copy();
+ return new DefaultedHttpParams(clone, this.defaults);
+ }
+
+ /**
+ * Retrieves the value of the parameter from the local collection and, if the
+ * parameter is not set locally, delegates its resolution to the default
+ * collection.
+ */
+ public Object getParameter(final String name) {
+ Object obj = this.local.getParameter(name);
+ if (obj == null && this.defaults != null) {
+ obj = this.defaults.getParameter(name);
+ }
+ return obj;
+ }
+
+ /**
+ * Attempts to remove the parameter from the local collection. This method
+ * <i>does not</i> modify the default collection.
+ */
+ public boolean removeParameter(final String name) {
+ return this.local.removeParameter(name);
+ }
+
+ /**
+ * Sets the parameter in the local collection. This method <i>does not</i>
+ * modify the default collection.
+ */
+ public HttpParams setParameter(final String name, final Object value) {
+ return this.local.setParameter(name, value);
+ }
+
+ public HttpParams getDefaults() {
+ return this.defaults;
+ }
+
+}
diff --git a/src/org/apache/http/params/HttpAbstractParamBean.java b/src/org/apache/http/params/HttpAbstractParamBean.java
new file mode 100644
index 0000000..8701a99
--- /dev/null
+++ b/src/org/apache/http/params/HttpAbstractParamBean.java
@@ -0,0 +1,44 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpAbstractParamBean.java $
+ * $Revision: 593937 $
+ * $Date: 2007-11-11 10:44:12 -0800 (Sun, 11 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+public abstract class HttpAbstractParamBean {
+
+ protected final HttpParams params;
+
+ public HttpAbstractParamBean (final HttpParams params) {
+ if (params == null)
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ this.params = params;
+ }
+
+}
diff --git a/src/org/apache/http/params/HttpConnectionParamBean.java b/src/org/apache/http/params/HttpConnectionParamBean.java
new file mode 100644
index 0000000..0b61346
--- /dev/null
+++ b/src/org/apache/http/params/HttpConnectionParamBean.java
@@ -0,0 +1,64 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpConnectionParamBean.java $
+ * $Revision: 593937 $
+ * $Date: 2007-11-11 10:44:12 -0800 (Sun, 11 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+public class HttpConnectionParamBean extends HttpAbstractParamBean {
+
+ public HttpConnectionParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ public void setSoTimeout (int soTimeout) {
+ HttpConnectionParams.setSoTimeout(params, soTimeout);
+ }
+
+ public void setTcpNoDelay (boolean tcpNoDelay) {
+ HttpConnectionParams.setTcpNoDelay(params, tcpNoDelay);
+ }
+
+ public void setSocketBufferSize (int socketBufferSize) {
+ HttpConnectionParams.setSocketBufferSize(params, socketBufferSize);
+ }
+
+ public void setLinger (int linger) {
+ HttpConnectionParams.setLinger(params, linger);
+ }
+
+ public void setConnectionTimeout (int connectionTimeout) {
+ HttpConnectionParams.setConnectionTimeout(params, connectionTimeout);
+ }
+
+ public void setStaleCheckingEnabled (boolean staleCheckingEnabled) {
+ HttpConnectionParams.setStaleCheckingEnabled(params, staleCheckingEnabled);
+ }
+
+}
diff --git a/src/org/apache/http/params/HttpConnectionParams.java b/src/org/apache/http/params/HttpConnectionParams.java
new file mode 100644
index 0000000..7918a66
--- /dev/null
+++ b/src/org/apache/http/params/HttpConnectionParams.java
@@ -0,0 +1,224 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpConnectionParams.java $
+ * $Revision: 576089 $
+ * $Date: 2007-09-16 05:39:56 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+/**
+ * An adaptor for accessing connection parameters in {@link HttpParams}.
+ * <br/>
+ * Note that the <i>implements</i> relation to {@link CoreConnectionPNames}
+ * is for compatibility with existing application code only. References to
+ * the parameter names should use the interface, not this class.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 576089 $
+ *
+ * @since 4.0
+ */
+public final class HttpConnectionParams implements CoreConnectionPNames {
+
+ /**
+ */
+ private HttpConnectionParams() {
+ super();
+ }
+
+ /**
+ * Returns the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
+ * timeout for waiting for data. A timeout value of zero is interpreted as an infinite
+ * timeout. This value is used when no socket timeout is set in the
+ * method parameters.
+ *
+ * @return timeout in milliseconds
+ */
+ public static int getSoTimeout(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter(CoreConnectionPNames.SO_TIMEOUT, 0);
+ }
+
+ /**
+ * Sets the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
+ * timeout for waiting for data. A timeout value of zero is interpreted as an infinite
+ * timeout. This value is used when no socket timeout is set in the
+ * method parameters.
+ *
+ * @param timeout Timeout in milliseconds
+ */
+ public static void setSoTimeout(final HttpParams params, int timeout) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
+
+ }
+
+ /**
+ * Tests if Nagle's algorithm is to be used.
+ *
+ * @return <tt>true</tt> if the Nagle's algorithm is to NOT be used
+ * (that is enable TCP_NODELAY), <tt>false</tt> otherwise.
+ */
+ public static boolean getTcpNoDelay(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (CoreConnectionPNames.TCP_NODELAY, true);
+ }
+
+ /**
+ * Determines whether Nagle's algorithm is to be used. The Nagle's algorithm
+ * tries to conserve bandwidth by minimizing the number of segments that are
+ * sent. When applications wish to decrease network latency and increase
+ * performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY).
+ * Data will be sent earlier, at the cost of an increase in bandwidth consumption.
+ *
+ * @param value <tt>true</tt> if the Nagle's algorithm is to NOT be used
+ * (that is enable TCP_NODELAY), <tt>false</tt> otherwise.
+ */
+ public static void setTcpNoDelay(final HttpParams params, boolean value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, value);
+ }
+
+ public static int getSocketBufferSize(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter
+ (CoreConnectionPNames.SOCKET_BUFFER_SIZE, -1);
+ }
+
+ public static void setSocketBufferSize(final HttpParams params, int size) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, size);
+ }
+
+ /**
+ * Returns linger-on-close timeout. Value <tt>0</tt> implies that the option is
+ * disabled. Value <tt>-1</tt> implies that the JRE default is used.
+ *
+ * @return the linger-on-close timeout
+ */
+ public static int getLinger(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter(CoreConnectionPNames.SO_LINGER, -1);
+ }
+
+ /**
+ * Returns linger-on-close timeout. This option disables/enables immediate return
+ * from a close() of a TCP Socket. Enabling this option with a non-zero Integer
+ * timeout means that a close() will block pending the transmission and
+ * acknowledgement of all data written to the peer, at which point the socket is
+ * closed gracefully. Value <tt>0</tt> implies that the option is
+ * disabled. Value <tt>-1</tt> implies that the JRE default is used.
+ *
+ * @param value the linger-on-close timeout
+ */
+ public static void setLinger(final HttpParams params, int value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter(CoreConnectionPNames.SO_LINGER, value);
+ }
+
+ /**
+ * Returns the timeout until a connection is etablished. A value of zero
+ * means the timeout is not used. The default value is zero.
+ *
+ * @return timeout in milliseconds.
+ */
+ public static int getConnectionTimeout(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter
+ (CoreConnectionPNames.CONNECTION_TIMEOUT, 0);
+ }
+
+ /**
+ * Sets the timeout until a connection is etablished. A value of zero
+ * means the timeout is not used. The default value is zero.
+ *
+ * @param timeout Timeout in milliseconds.
+ */
+ public static void setConnectionTimeout(final HttpParams params, int timeout) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter
+ (CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
+ }
+
+ /**
+ * Tests whether stale connection check is to be used. Disabling
+ * stale connection check may result in slight performance improvement
+ * at the risk of getting an I/O error when executing a request over a
+ * connection that has been closed at the server side.
+ *
+ * @return <tt>true</tt> if stale connection check is to be used,
+ * <tt>false</tt> otherwise.
+ */
+ public static boolean isStaleCheckingEnabled(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (CoreConnectionPNames.STALE_CONNECTION_CHECK, true);
+ }
+
+ /**
+ * Defines whether stale connection check is to be used. Disabling
+ * stale connection check may result in slight performance improvement
+ * at the risk of getting an I/O error when executing a request over a
+ * connection that has been closed at the server side.
+ *
+ * @param value <tt>true</tt> if stale connection check is to be used,
+ * <tt>false</tt> otherwise.
+ */
+ public static void setStaleCheckingEnabled(final HttpParams params, boolean value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter
+ (CoreConnectionPNames.STALE_CONNECTION_CHECK, value);
+ }
+
+}
diff --git a/src/org/apache/http/params/HttpParams.java b/src/org/apache/http/params/HttpParams.java
new file mode 100644
index 0000000..ba901a2
--- /dev/null
+++ b/src/org/apache/http/params/HttpParams.java
@@ -0,0 +1,187 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpParams.java $
+ * $Revision: 610763 $
+ * $Date: 2008-01-10 04:01:13 -0800 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+/**
+ * Represents a collection of HTTP protocol and framework parameters.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 610763 $
+ *
+ * @since 4.0
+ */
+public interface HttpParams {
+
+ /**
+ * Obtains the value of the given parameter.
+ *
+ * @param name the parent name.
+ *
+ * @return an object that represents the value of the parameter,
+ * <code>null</code> if the parameter is not set or if it
+ * is explicitly set to <code>null</code>
+ *
+ * @see #setParameter(String, Object)
+ */
+ Object getParameter(String name);
+
+ /**
+ * Assigns the value to the parameter with the given name.
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setParameter(String name, Object value);
+
+ /**
+ * Creates a copy of these parameters.
+ *
+ * @return a new set of parameters holding the same values as this one
+ */
+ HttpParams copy();
+
+ /**
+ * Removes the parameter with the specified name.
+ *
+ * @param name parameter name
+ *
+ * @return true if the parameter existed and has been removed, false else.
+ */
+ boolean removeParameter(String name);
+
+ /**
+ * Returns a {@link Long} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Long} that represents the value of the parameter.
+ *
+ * @see #setLongParameter(String, long)
+ */
+ long getLongParameter(String name, long defaultValue);
+
+ /**
+ * Assigns a {@link Long} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setLongParameter(String name, long value);
+
+ /**
+ * Returns an {@link Integer} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Integer} that represents the value of the parameter.
+ *
+ * @see #setIntParameter(String, int)
+ */
+ int getIntParameter(String name, int defaultValue);
+
+ /**
+ * Assigns an {@link Integer} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setIntParameter(String name, int value);
+
+ /**
+ * Returns a {@link Double} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Double} that represents the value of the parameter.
+ *
+ * @see #setDoubleParameter(String, double)
+ */
+ double getDoubleParameter(String name, double defaultValue);
+
+ /**
+ * Assigns a {@link Double} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setDoubleParameter(String name, double value);
+
+ /**
+ * Returns a {@link Boolean} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Boolean} that represents the value of the parameter.
+ *
+ * @see #setBooleanParameter(String, boolean)
+ */
+ boolean getBooleanParameter(String name, boolean defaultValue);
+
+ /**
+ * Assigns a {@link Boolean} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setBooleanParameter(String name, boolean value);
+
+ /**
+ * Checks if a boolean parameter is set to <code>true</code>.
+ *
+ * @param name parameter name
+ *
+ * @return <tt>true</tt> if the parameter is set to value <tt>true</tt>,
+ * <tt>false</tt> if it is not set or set to <code>false</code>
+ */
+ boolean isParameterTrue(String name);
+
+ /**
+ * Checks if a boolean parameter is not set or <code>false</code>.
+ *
+ * @param name parameter name
+ *
+ * @return <tt>true</tt> if the parameter is either not set or
+ * set to value <tt>false</tt>,
+ * <tt>false</tt> if it is set to <code>true</code>
+ */
+ boolean isParameterFalse(String name);
+
+}
diff --git a/src/org/apache/http/params/HttpProtocolParamBean.java b/src/org/apache/http/params/HttpProtocolParamBean.java
new file mode 100644
index 0000000..6273430
--- /dev/null
+++ b/src/org/apache/http/params/HttpProtocolParamBean.java
@@ -0,0 +1,62 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpProtocolParamBean.java $
+ * $Revision: 593937 $
+ * $Date: 2007-11-11 10:44:12 -0800 (Sun, 11 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+import org.apache.http.HttpVersion;
+
+public class HttpProtocolParamBean extends HttpAbstractParamBean {
+
+ public HttpProtocolParamBean (final HttpParams params) {
+ super(params);
+ }
+
+ public void setHttpElementCharset (final String httpElementCharset) {
+ HttpProtocolParams.setHttpElementCharset(params, httpElementCharset);
+ }
+
+ public void setContentCharset (final String contentCharset) {
+ HttpProtocolParams.setContentCharset(params, contentCharset);
+ }
+
+ public void setVersion (final HttpVersion version) {
+ HttpProtocolParams.setVersion(params, version);
+ }
+
+ public void setUserAgent (final String userAgent) {
+ HttpProtocolParams.setUserAgent(params, userAgent);
+ }
+
+ public void setUseExpectContinue (boolean useExpectContinue) {
+ HttpProtocolParams.setUseExpectContinue(params, useExpectContinue);
+ }
+
+}
diff --git a/src/org/apache/http/params/HttpProtocolParams.java b/src/org/apache/http/params/HttpProtocolParams.java
new file mode 100644
index 0000000..71e9c67
--- /dev/null
+++ b/src/org/apache/http/params/HttpProtocolParams.java
@@ -0,0 +1,176 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpProtocolParams.java $
+ * $Revision: 576089 $
+ * $Date: 2007-09-16 05:39:56 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * This class implements an adaptor around the {@link HttpParams} interface
+ * to simplify manipulation of the HTTP protocol specific parameters.
+ * <br/>
+ * Note that the <i>implements</i> relation to {@link CoreProtocolPNames}
+ * is for compatibility with existing application code only. References to
+ * the parameter names should use the interface, not this class.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 576089 $
+ *
+ * @since 4.0
+ *
+ * @see CoreProtocolPNames
+ */
+public final class HttpProtocolParams implements CoreProtocolPNames {
+
+ /**
+ */
+ private HttpProtocolParams() {
+ super();
+ }
+
+ /**
+ * Returns the charset to be used for writing HTTP headers.
+ * @return The charset
+ */
+ public static String getHttpElementCharset(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ String charset = (String) params.getParameter
+ (CoreProtocolPNames.HTTP_ELEMENT_CHARSET);
+ if (charset == null) {
+ charset = HTTP.DEFAULT_PROTOCOL_CHARSET;
+ }
+ return charset;
+ }
+
+ /**
+ * Sets the charset to be used for writing HTTP headers.
+ * @param charset The charset
+ */
+ public static void setHttpElementCharset(final HttpParams params, final String charset) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET, charset);
+ }
+
+ /**
+ * Returns the default charset to be used for writing content body,
+ * when no charset explicitly specified.
+ * @return The charset
+ */
+ public static String getContentCharset(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ String charset = (String) params.getParameter
+ (CoreProtocolPNames.HTTP_CONTENT_CHARSET);
+ if (charset == null) {
+ charset = HTTP.DEFAULT_CONTENT_CHARSET;
+ }
+ return charset;
+ }
+
+ /**
+ * Sets the default charset to be used for writing content body,
+ * when no charset explicitly specified.
+ * @param charset The charset
+ */
+ public static void setContentCharset(final HttpParams params, final String charset) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, charset);
+ }
+
+ /**
+ * Returns {@link ProtocolVersion protocol version} to be used per default.
+ *
+ * @return {@link ProtocolVersion protocol version}
+ */
+ public static ProtocolVersion getVersion(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ Object param = params.getParameter
+ (CoreProtocolPNames.PROTOCOL_VERSION);
+ if (param == null) {
+ return HttpVersion.HTTP_1_1;
+ }
+ return (ProtocolVersion)param;
+ }
+
+ /**
+ * Assigns the {@link ProtocolVersion protocol version} to be used by the
+ * HTTP methods that this collection of parameters applies to.
+ *
+ * @param version the {@link ProtocolVersion protocol version}
+ */
+ public static void setVersion(final HttpParams params, final ProtocolVersion version) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, version);
+ }
+
+ public static String getUserAgent(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return (String) params.getParameter(CoreProtocolPNames.USER_AGENT);
+ }
+
+ public static void setUserAgent(final HttpParams params, final String useragent) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setParameter(CoreProtocolPNames.USER_AGENT, useragent);
+ }
+
+ public static boolean useExpectContinue(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
+ }
+
+ public static void setUseExpectContinue(final HttpParams params, boolean b) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, b);
+ }
+}
diff --git a/src/org/apache/http/params/package.html b/src/org/apache/http/params/package.html
new file mode 100644
index 0000000..3943053
--- /dev/null
+++ b/src/org/apache/http/params/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/package.html $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+The parameterization framework for HTTP components.
+
+</body>
+</html>
diff --git a/src/org/apache/http/protocol/BasicHttpContext.java b/src/org/apache/http/protocol/BasicHttpContext.java
new file mode 100644
index 0000000..9b4e2b3
--- /dev/null
+++ b/src/org/apache/http/protocol/BasicHttpContext.java
@@ -0,0 +1,95 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/BasicHttpContext.java $
+ * $Revision: 654882 $
+ * $Date: 2008-05-09 09:58:59 -0700 (Fri, 09 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Default implementation of the {@link HttpContext HttpContext}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 654882 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpContext implements HttpContext {
+
+ private final HttpContext parentContext;
+ private Map map = null;
+
+ public BasicHttpContext() {
+ this(null);
+ }
+
+ public BasicHttpContext(final HttpContext parentContext) {
+ super();
+ this.parentContext = parentContext;
+ }
+
+ public Object getAttribute(final String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("Id may not be null");
+ }
+ Object obj = null;
+ if (this.map != null) {
+ obj = this.map.get(id);
+ }
+ if (obj == null && this.parentContext != null) {
+ obj = this.parentContext.getAttribute(id);
+ }
+ return obj;
+ }
+
+ public void setAttribute(final String id, final Object obj) {
+ if (id == null) {
+ throw new IllegalArgumentException("Id may not be null");
+ }
+ if (this.map == null) {
+ this.map = new HashMap();
+ }
+ this.map.put(id, obj);
+ }
+
+ public Object removeAttribute(final String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("Id may not be null");
+ }
+ if (this.map != null) {
+ return this.map.remove(id);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/BasicHttpProcessor.java b/src/org/apache/http/protocol/BasicHttpProcessor.java
new file mode 100644
index 0000000..3caec72
--- /dev/null
+++ b/src/org/apache/http/protocol/BasicHttpProcessor.java
@@ -0,0 +1,337 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/BasicHttpProcessor.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+
+/**
+ * Keeps lists of interceptors for processing requests and responses.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author Andrea Selva
+ *
+ * @version $Revision: 613298 $
+ *
+ * @since 4.0
+ */
+public final class BasicHttpProcessor implements
+ HttpProcessor, HttpRequestInterceptorList, HttpResponseInterceptorList, Cloneable {
+
+ protected List requestInterceptors = null;
+ protected List responseInterceptors = null;
+
+
+ // non-Javadoc, see interface HttpRequestInterceptorList
+ public void addRequestInterceptor(final HttpRequestInterceptor itcp) {
+
+ if (itcp == null) {
+ return;
+ }
+ if (this.requestInterceptors == null) {
+ this.requestInterceptors = new ArrayList();
+ }
+ this.requestInterceptors.add(itcp);
+ }
+
+ // non-Javadoc, see interface HttpRequestInterceptorList
+ public void addRequestInterceptor(final HttpRequestInterceptor itcp,
+ int index) {
+ if (index < 0) {
+ throw new IndexOutOfBoundsException(String.valueOf(index));
+ }
+ if (itcp == null) {
+ return;
+ }
+
+ if (this.requestInterceptors == null) {
+ if (index > 0) {
+ throw new IndexOutOfBoundsException(String.valueOf(index));
+ }
+ this.requestInterceptors = new ArrayList();
+ }
+ this.requestInterceptors.add(index, itcp);
+ }
+
+
+ public void addResponseInterceptor(HttpResponseInterceptor itcp,
+ int index) {
+ if (index < 0) {
+ throw new IndexOutOfBoundsException(String.valueOf(index));
+ }
+ if (itcp == null) {
+ return;
+ }
+
+ if (this.responseInterceptors == null) {
+ if (index > 0) {
+ throw new IndexOutOfBoundsException(String.valueOf(index));
+ }
+ this.responseInterceptors = new ArrayList();
+ }
+ this.responseInterceptors.add(index, itcp);
+ }
+
+
+ // non-Javadoc, see interface HttpRequestInterceptorList
+ public void removeRequestInterceptorByClass(final Class clazz) {
+ if (this.requestInterceptors == null) {
+ return;
+ }
+ for (Iterator it = this.requestInterceptors.iterator();
+ it.hasNext(); ) {
+ Object request = it.next();
+ if (request.getClass().equals(clazz)) {
+ it.remove();
+ }
+ }
+ }
+
+ // non-Javadoc, see interface HttpResponseInterceptorList
+ public void removeResponseInterceptorByClass(final Class clazz) {
+ if (this.responseInterceptors == null) {
+ return;
+ }
+ for (Iterator it = this.responseInterceptors.iterator();
+ it.hasNext(); ) {
+ Object request = it.next();
+ if (request.getClass().equals(clazz)) {
+ it.remove();
+ }
+ }
+ }
+
+ /**
+ * Same as {@link #addRequestInterceptor(HttpRequestInterceptor) addRequestInterceptor}.
+ *
+ * @param interceptor the interceptor to add
+ */
+ public final
+ void addInterceptor(final HttpRequestInterceptor interceptor) {
+ addRequestInterceptor(interceptor);
+ }
+
+ public final
+ void addInterceptor(final HttpRequestInterceptor interceptor,
+ int index) {
+ addRequestInterceptor(interceptor, index);
+ }
+
+
+ // non-Javadoc, see interface HttpRequestInterceptorList
+ public int getRequestInterceptorCount() {
+ return (this.requestInterceptors == null) ?
+ 0 : this.requestInterceptors.size();
+ }
+
+
+ // non-Javadoc, see interface HttpRequestInterceptorList
+ public HttpRequestInterceptor getRequestInterceptor(int index) {
+
+ if ((this.requestInterceptors == null) ||
+ (index < 0) || (index >= this.requestInterceptors.size()))
+ return null;
+
+ return (HttpRequestInterceptor) this.requestInterceptors.get(index);
+ }
+
+
+ // non-Javadoc, see interface HttpRequestInterceptorList
+ public void clearRequestInterceptors() {
+ this.requestInterceptors = null;
+ }
+
+
+
+ // non-Javadoc, see interface HttpResponseInterceptorList
+ public void addResponseInterceptor(final HttpResponseInterceptor itcp) {
+ if (itcp == null) {
+ return;
+ }
+ if (this.responseInterceptors == null) {
+ this.responseInterceptors = new ArrayList();
+ }
+ this.responseInterceptors.add(itcp);
+ }
+
+ /**
+ * Same as {@link #addResponseInterceptor(HttpResponseInterceptor) addResponseInterceptor}.
+ *
+ * @param interceptor the interceptor to add
+ */
+ public final
+ void addInterceptor(final HttpResponseInterceptor interceptor) {
+ addResponseInterceptor(interceptor);
+ }
+
+ public final void addInterceptor(final HttpResponseInterceptor interceptor,
+ int index) {
+ addResponseInterceptor(interceptor, index);
+ }
+
+
+
+ // non-Javadoc, see interface HttpResponseInterceptorList
+ public int getResponseInterceptorCount() {
+ return (this.responseInterceptors == null) ?
+ 0 : this.responseInterceptors.size();
+ }
+
+
+ // non-Javadoc, see interface HttpResponseInterceptorList
+ public HttpResponseInterceptor getResponseInterceptor(int index) {
+
+ if ((this.responseInterceptors == null) ||
+ (index < 0) || (index >= this.responseInterceptors.size()))
+ return null;
+
+ return (HttpResponseInterceptor) this.responseInterceptors.get(index);
+ }
+
+
+ // non-Javadoc, see interface HttpResponseInterceptorList
+ public void clearResponseInterceptors() {
+ this.responseInterceptors = null;
+ }
+
+
+ /**
+ * Sets the interceptor lists.
+ * First, both interceptor lists maintained by this processor
+ * will be cleared.
+ * Subsequently,
+ * elements of the argument list that are request interceptors will be
+ * added to the request interceptor list.
+ * Elements that are response interceptors will be
+ * added to the response interceptor list.
+ * Elements that are both request and response interceptor will be
+ * added to both lists.
+ * Elements that are neither request nor response interceptor
+ * will be ignored.
+ *
+ * @param list the list of request and response interceptors
+ * from which to initialize
+ */
+ public void setInterceptors(final List list) {
+ if (list == null) {
+ throw new IllegalArgumentException("List must not be null.");
+ }
+ if (this.requestInterceptors != null) {
+ this.requestInterceptors.clear();
+ }
+ if (this.responseInterceptors != null) {
+ this.responseInterceptors.clear();
+ }
+ for (int i = 0; i < list.size(); i++) {
+ Object obj = list.get(i);
+ if (obj instanceof HttpRequestInterceptor) {
+ addInterceptor((HttpRequestInterceptor)obj);
+ }
+ if (obj instanceof HttpResponseInterceptor) {
+ addInterceptor((HttpResponseInterceptor)obj);
+ }
+ }
+ }
+
+ /**
+ * Clears both interceptor lists maintained by this processor.
+ */
+ public void clearInterceptors() {
+ clearRequestInterceptors();
+ clearResponseInterceptors();
+ }
+
+ // non-Javadoc, see interface HttpRequestInterceptor (via HttpProcessor)
+ public void process(
+ final HttpRequest request,
+ final HttpContext context)
+ throws IOException, HttpException {
+ if (this.requestInterceptors != null) {
+ for (int i = 0; i < this.requestInterceptors.size(); i++) {
+ HttpRequestInterceptor interceptor =
+ (HttpRequestInterceptor) this.requestInterceptors.get(i);
+ interceptor.process(request, context);
+ }
+ }
+ }
+
+ // non-Javadoc, see interface HttpResponseInterceptor (via HttpProcessor)
+ public void process(
+ final HttpResponse response,
+ final HttpContext context)
+ throws IOException, HttpException {
+ if (this.responseInterceptors != null) {
+ for (int i = 0; i < this.responseInterceptors.size(); i++) {
+ HttpResponseInterceptor interceptor =
+ (HttpResponseInterceptor) this.responseInterceptors.get(i);
+ interceptor.process(response, context);
+ }
+ }
+ }
+
+ protected void copyInterceptors(final BasicHttpProcessor target) {
+ if (this.requestInterceptors != null) {
+ target.requestInterceptors =
+ new ArrayList(this.requestInterceptors);
+ }
+ if (this.responseInterceptors != null) {
+ target.responseInterceptors =
+ new ArrayList(this.responseInterceptors);
+ }
+ }
+
+ /**
+ * Creates a copy of this instance
+ *
+ * @return new instance of the BasicHttpProcessor
+ */
+ public BasicHttpProcessor copy() {
+ BasicHttpProcessor clone = new BasicHttpProcessor();
+ copyInterceptors(clone);
+ return clone;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ BasicHttpProcessor clone = (BasicHttpProcessor) super.clone();
+ copyInterceptors(clone);
+ return clone;
+ }
+
+}
diff --git a/src/org/apache/http/protocol/DefaultedHttpContext.java b/src/org/apache/http/protocol/DefaultedHttpContext.java
new file mode 100644
index 0000000..986f1a6
--- /dev/null
+++ b/src/org/apache/http/protocol/DefaultedHttpContext.java
@@ -0,0 +1,79 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/DefaultedHttpContext.java $
+ * $Revision: 654882 $
+ * $Date: 2008-05-09 09:58:59 -0700 (Fri, 09 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+/**
+ * {@link HttpContext} implementation that delegates resolution of an attribute
+ * to the given default {@link HttpContext} instance if the attribute is not
+ * present in the local one. The state of the local context can be mutated,
+ * whereas the default context is treated as read-only.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 654882 $
+ */
+public final class DefaultedHttpContext implements HttpContext {
+
+ private final HttpContext local;
+ private final HttpContext defaults;
+
+ public DefaultedHttpContext(final HttpContext local, final HttpContext defaults) {
+ super();
+ if (local == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+ this.local = local;
+ this.defaults = defaults;
+ }
+
+ public Object getAttribute(final String id) {
+ Object obj = this.local.getAttribute(id);
+ if (obj == null) {
+ return this.defaults.getAttribute(id);
+ } else {
+ return obj;
+ }
+ }
+
+ public Object removeAttribute(final String id) {
+ return this.local.removeAttribute(id);
+ }
+
+ public void setAttribute(final String id, final Object obj) {
+ this.local.setAttribute(id, obj);
+ }
+
+ public HttpContext getDefaults() {
+ return this.defaults;
+ }
+
+}
diff --git a/src/org/apache/http/protocol/ExecutionContext.java b/src/org/apache/http/protocol/ExecutionContext.java
new file mode 100644
index 0000000..d14acb5
--- /dev/null
+++ b/src/org/apache/http/protocol/ExecutionContext.java
@@ -0,0 +1,52 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/ExecutionContext.java $
+ * $Revision: 558154 $
+ * $Date: 2007-07-20 14:29:02 -0700 (Fri, 20 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+/**
+ * {@link HttpContext Context} attribute names for protocol execution.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 558154 $
+ *
+ * @since 4.0
+ */
+public interface ExecutionContext {
+
+ public static final String HTTP_CONNECTION = "http.connection";
+ public static final String HTTP_REQUEST = "http.request";
+ public static final String HTTP_RESPONSE = "http.response";
+ public static final String HTTP_TARGET_HOST = "http.target_host";
+ public static final String HTTP_PROXY_HOST = "http.proxy_host";
+ public static final String HTTP_REQ_SENT = "http.request_sent";
+
+}
diff --git a/src/org/apache/http/protocol/HTTP.java b/src/org/apache/http/protocol/HTTP.java
new file mode 100644
index 0000000..de76ca6
--- /dev/null
+++ b/src/org/apache/http/protocol/HTTP.java
@@ -0,0 +1,99 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HTTP.java $
+ * $Revision: 555989 $
+ * $Date: 2007-07-13 06:33:39 -0700 (Fri, 13 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+/**
+ * Constants and static helpers related to the HTTP protocol.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 555989 $
+ *
+ * @since 4.0
+ */
+public final class HTTP {
+
+ public static final int CR = 13; // <US-ASCII CR, carriage return (13)>
+ public static final int LF = 10; // <US-ASCII LF, linefeed (10)>
+ public static final int SP = 32; // <US-ASCII SP, space (32)>
+ public static final int HT = 9; // <US-ASCII HT, horizontal-tab (9)>
+
+ /** HTTP header definitions */
+ public static final String TRANSFER_ENCODING = "Transfer-Encoding";
+ public static final String CONTENT_LEN = "Content-Length";
+ public static final String CONTENT_TYPE = "Content-Type";
+ public static final String CONTENT_ENCODING = "Content-Encoding";
+ public static final String EXPECT_DIRECTIVE = "Expect";
+ public static final String CONN_DIRECTIVE = "Connection";
+ public static final String TARGET_HOST = "Host";
+ public static final String USER_AGENT = "User-Agent";
+ public static final String DATE_HEADER = "Date";
+ public static final String SERVER_HEADER = "Server";
+
+ /** HTTP expectations */
+ public static final String EXPECT_CONTINUE = "100-Continue";
+
+ /** HTTP connection control */
+ public static final String CONN_CLOSE = "Close";
+ public static final String CONN_KEEP_ALIVE = "Keep-Alive";
+
+ /** Transfer encoding definitions */
+ public static final String CHUNK_CODING = "chunked";
+ public static final String IDENTITY_CODING = "identity";
+
+ /** Common charset definitions */
+ public static final String UTF_8 = "UTF-8";
+ public static final String UTF_16 = "UTF-16";
+ public static final String US_ASCII = "US-ASCII";
+ public static final String ASCII = "ASCII";
+ public static final String ISO_8859_1 = "ISO-8859-1";
+
+ /** Default charsets */
+ public static final String DEFAULT_CONTENT_CHARSET = ISO_8859_1;
+ public static final String DEFAULT_PROTOCOL_CHARSET = US_ASCII;
+
+ /** Content type definitions */
+ public final static String OCTET_STREAM_TYPE = "application/octet-stream";
+ public final static String PLAIN_TEXT_TYPE = "text/plain";
+ public final static String CHARSET_PARAM = "; charset=";
+
+ /** Default content type */
+ public final static String DEFAULT_CONTENT_TYPE = OCTET_STREAM_TYPE;
+
+ public static boolean isWhitespace(char ch) {
+ return ch == SP || ch == HT || ch == CR || ch == LF;
+ }
+
+ private HTTP() {
+ }
+
+}
diff --git a/src/org/apache/http/protocol/HttpContext.java b/src/org/apache/http/protocol/HttpContext.java
new file mode 100644
index 0000000..bcf36fd
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpContext.java
@@ -0,0 +1,58 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpContext.java $
+ * $Revision: 558111 $
+ * $Date: 2007-07-20 13:01:50 -0700 (Fri, 20 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+/**
+ * A context for executing a request.
+ * The context is used to tie together the request, the response,
+ * and optional application data. It is also used for internal data.
+ * Attribute names starting with the prefix "http." are
+ * {@link #RESERVED_PREFIX reserved} for internal data.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 558111 $
+ *
+ * @since 4.0
+ */
+public interface HttpContext {
+
+ /** The prefix reserved for use by HTTP components. "http." */
+ public static final String RESERVED_PREFIX = "http.";
+
+ Object getAttribute(String id);
+
+ void setAttribute(String id, Object obj);
+
+ Object removeAttribute(String id);
+
+}
diff --git a/src/org/apache/http/protocol/HttpDateGenerator.java b/src/org/apache/http/protocol/HttpDateGenerator.java
new file mode 100644
index 0000000..bfb0863
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpDateGenerator.java
@@ -0,0 +1,81 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpDateGenerator.java $
+ * $Revision: 548066 $
+ * $Date: 2007-06-17 09:51:55 -0700 (Sun, 17 Jun 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+
+/**
+ * Generates a date in the format required by the HTTP protocol.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 548066 $
+ *
+ * @since 4.0
+ */
+public class HttpDateGenerator {
+
+ /** Date format pattern used to generate the header in RFC 1123 format. */
+ public static final
+ String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+ /** The time zone to use in the date header. */
+ public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+
+ private final DateFormat dateformat;
+
+ private long dateAsLong = 0L;
+ private String dateAsText = null;
+
+ public HttpDateGenerator() {
+ super();
+ this.dateformat = new SimpleDateFormat(PATTERN_RFC1123, Locale.US);
+ this.dateformat.setTimeZone(GMT);
+ }
+
+ public synchronized String getCurrentDate() {
+ long now = System.currentTimeMillis();
+ if (now - this.dateAsLong > 1000) {
+ // Generate new date string
+ this.dateAsText = this.dateformat.format(new Date(now));
+ this.dateAsLong = now;
+ }
+ return this.dateAsText;
+ }
+
+}
diff --git a/src/org/apache/http/protocol/HttpExpectationVerifier.java b/src/org/apache/http/protocol/HttpExpectationVerifier.java
new file mode 100644
index 0000000..9fa4316
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpExpectationVerifier.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpExpectationVerifier.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+
+/**
+ * Defines an interface to verify whether an incoming HTTP request meets
+ * the target server's expectations.
+ *<p>
+ * The Expect request-header field is used to indicate that particular
+ * server behaviors are required by the client.
+ *</p>
+ *<pre>
+ * Expect = "Expect" ":" 1#expectation
+ *
+ * expectation = "100-continue" | expectation-extension
+ * expectation-extension = token [ "=" ( token | quoted-string )
+ * *expect-params ]
+ * expect-params = ";" token [ "=" ( token | quoted-string ) ]
+ *</pre>
+ *<p>
+ * A server that does not understand or is unable to comply with any of
+ * the expectation values in the Expect field of a request MUST respond
+ * with appropriate error status. The server MUST respond with a 417
+ * (Expectation Failed) status if any of the expectations cannot be met
+ * or, if there are other problems with the request, some other 4xx
+ * status.
+ *</p>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 613298 $
+ *
+ * @since 4.0
+ */
+public interface HttpExpectationVerifier {
+
+ void verify(HttpRequest request, HttpResponse response, HttpContext context)
+ throws HttpException;
+
+}
diff --git a/src/org/apache/http/protocol/HttpProcessor.java b/src/org/apache/http/protocol/HttpProcessor.java
new file mode 100644
index 0000000..489220d
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpProcessor.java
@@ -0,0 +1,56 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpProcessor.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponseInterceptor;
+
+/**
+ * Performs interceptor processing of requests and responses.
+ * Specific interceptors typically interpret or update message headers,
+ * and they may wrap the message entity for example to implement a
+ * specific transport or content encoding.
+ * A <code>HttpProcessor</code> typically maintains a list of
+ * interceptors that will be applied to a request or response.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public interface HttpProcessor
+ extends HttpRequestInterceptor, HttpResponseInterceptor {
+
+ // no additional methods
+}
diff --git a/src/org/apache/http/protocol/HttpRequestExecutor.java b/src/org/apache/http/protocol/HttpRequestExecutor.java
new file mode 100644
index 0000000..71fa75a
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpRequestExecutor.java
@@ -0,0 +1,322 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestExecutor.java $
+ * $Revision: 576073 $
+ * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+import java.net.ProtocolException;
+
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.params.CoreProtocolPNames;
+
+/**
+ * Sends HTTP requests and receives the responses.
+ * Takes care of request preprocessing and response postprocessing
+ * by the respective interceptors.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 576073 $
+ *
+ * @since 4.0
+ */
+public class HttpRequestExecutor {
+
+ /**
+ * Create a new request executor.
+ */
+ public HttpRequestExecutor() {
+ super();
+ }
+
+ /**
+ * Decide whether a response comes with an entity.
+ * The implementation in this class is based on RFC 2616.
+ * Unknown methods and response codes are supposed to
+ * indicate responses with an entity.
+ * <br/>
+ * Derived executors can override this method to handle
+ * methods and response codes not specified in RFC 2616.
+ *
+ * @param request the request, to obtain the executed method
+ * @param response the response, to obtain the status code
+ */
+ protected boolean canResponseHaveBody(final HttpRequest request,
+ final HttpResponse response) {
+
+ if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) {
+ return false;
+ }
+ int status = response.getStatusLine().getStatusCode();
+ return status >= HttpStatus.SC_OK
+ && status != HttpStatus.SC_NO_CONTENT
+ && status != HttpStatus.SC_NOT_MODIFIED
+ && status != HttpStatus.SC_RESET_CONTENT;
+ }
+
+ /**
+ * Synchronously send a request and obtain the response.
+ *
+ * @param request the request to send. It will be preprocessed.
+ * @param conn the open connection over which to send
+ *
+ * @return the response to the request, postprocessed
+ *
+ * @throws HttpException in case of a protocol or processing problem
+ * @throws IOException in case of an I/O problem
+ */
+ public HttpResponse execute(
+ final HttpRequest request,
+ final HttpClientConnection conn,
+ final HttpContext context)
+ throws IOException, HttpException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (conn == null) {
+ throw new IllegalArgumentException("Client connection may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ try {
+ HttpResponse response = doSendRequest(request, conn, context);
+ if (response == null) {
+ response = doReceiveResponse(request, conn, context);
+ }
+ return response;
+ } catch (IOException ex) {
+ conn.close();
+ throw ex;
+ } catch (HttpException ex) {
+ conn.close();
+ throw ex;
+ } catch (RuntimeException ex) {
+ conn.close();
+ throw ex;
+ }
+ }
+
+ /**
+ * Prepare a request for sending.
+ *
+ * @param request the request to prepare
+ * @param processor the processor to use
+ * @param context the context for sending the request
+ *
+ * @throws HttpException in case of a protocol or processing problem
+ * @throws IOException in case of an I/O problem
+ */
+ public void preProcess(
+ final HttpRequest request,
+ final HttpProcessor processor,
+ final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (processor == null) {
+ throw new IllegalArgumentException("HTTP processor may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+ processor.process(request, context);
+ }
+
+ /**
+ * Send a request over a connection.
+ * This method also handles the expect-continue handshake if necessary.
+ * If it does not have to handle an expect-continue handshake, it will
+ * not use the connection for reading or anything else that depends on
+ * data coming in over the connection.
+ *
+ * @param request the request to send, already
+ * {@link #preProcess preprocessed}
+ * @param conn the connection over which to send the request,
+ * already established
+ * @param context the context for sending the request
+ *
+ * @return a terminal response received as part of an expect-continue
+ * handshake, or
+ * <code>null</code> if the expect-continue handshake is not used
+ *
+ * @throws HttpException in case of a protocol or processing problem
+ * @throws IOException in case of an I/O problem
+ */
+ protected HttpResponse doSendRequest(
+ final HttpRequest request,
+ final HttpClientConnection conn,
+ final HttpContext context)
+ throws IOException, HttpException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (conn == null) {
+ throw new IllegalArgumentException("HTTP connection may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ HttpResponse response = null;
+ context.setAttribute(ExecutionContext.HTTP_REQ_SENT, Boolean.FALSE);
+
+ conn.sendRequestHeader(request);
+ if (request instanceof HttpEntityEnclosingRequest) {
+ // Check for expect-continue handshake. We have to flush the
+ // headers and wait for an 100-continue response to handle it.
+ // If we get a different response, we must not send the entity.
+ boolean sendentity = true;
+ final ProtocolVersion ver =
+ request.getRequestLine().getProtocolVersion();
+ if (((HttpEntityEnclosingRequest) request).expectContinue() &&
+ !ver.lessEquals(HttpVersion.HTTP_1_0)) {
+
+ conn.flush();
+ // As suggested by RFC 2616 section 8.2.3, we don't wait for a
+ // 100-continue response forever. On timeout, send the entity.
+ int tms = request.getParams().getIntParameter(
+ CoreProtocolPNames.WAIT_FOR_CONTINUE, 2000);
+
+ if (conn.isResponseAvailable(tms)) {
+ response = conn.receiveResponseHeader();
+ if (canResponseHaveBody(request, response)) {
+ conn.receiveResponseEntity(response);
+ }
+ int status = response.getStatusLine().getStatusCode();
+ if (status < 200) {
+ if (status != HttpStatus.SC_CONTINUE) {
+ throw new ProtocolException(
+ "Unexpected response: " + response.getStatusLine());
+ }
+ // discard 100-continue
+ response = null;
+ } else {
+ sendentity = false;
+ }
+ }
+ }
+ if (sendentity) {
+ conn.sendRequestEntity((HttpEntityEnclosingRequest) request);
+ }
+ }
+ conn.flush();
+ context.setAttribute(ExecutionContext.HTTP_REQ_SENT, Boolean.TRUE);
+ return response;
+ }
+
+ /**
+ * Wait for and receive a response.
+ * This method will automatically ignore intermediate responses
+ * with status code 1xx.
+ *
+ * @param request the request for which to obtain the response
+ * @param conn the connection over which the request was sent
+ * @param context the context for receiving the response
+ *
+ * @return the final response, not yet post-processed
+ *
+ * @throws HttpException in case of a protocol or processing problem
+ * @throws IOException in case of an I/O problem
+ */
+ protected HttpResponse doReceiveResponse(
+ final HttpRequest request,
+ final HttpClientConnection conn,
+ final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (conn == null) {
+ throw new IllegalArgumentException("HTTP connection may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+
+ HttpResponse response = null;
+ int statuscode = 0;
+
+ while (response == null || statuscode < HttpStatus.SC_OK) {
+
+ response = conn.receiveResponseHeader();
+ if (canResponseHaveBody(request, response)) {
+ conn.receiveResponseEntity(response);
+ }
+ statuscode = response.getStatusLine().getStatusCode();
+
+ } // while intermediate response
+
+ return response;
+
+ }
+
+ /**
+ * Finish a response.
+ * This includes post-processing of the response object.
+ * It does <i>not</i> read the response entity, if any.
+ * It does <i>not</i> allow for immediate re-use of the
+ * connection over which the response is coming in.
+ *
+ * @param response the response object to finish
+ * @param processor the processor to use
+ * @param context the context for post-processing the response
+ *
+ * @throws HttpException in case of a protocol or processing problem
+ * @throws IOException in case of an I/O problem
+ */
+ public void postProcess(
+ final HttpResponse response,
+ final HttpProcessor processor,
+ final HttpContext context)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ if (processor == null) {
+ throw new IllegalArgumentException("HTTP processor may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+ processor.process(response, context);
+ }
+
+} // class HttpRequestExecutor
diff --git a/src/org/apache/http/protocol/HttpRequestHandler.java b/src/org/apache/http/protocol/HttpRequestHandler.java
new file mode 100644
index 0000000..7494353
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpRequestHandler.java
@@ -0,0 +1,53 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestHandler.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+
+/**
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 613298 $
+ *
+ * @since 4.0
+ */
+public interface HttpRequestHandler {
+
+ void handle(HttpRequest request, HttpResponse response, HttpContext context)
+ throws HttpException, IOException;
+
+}
diff --git a/src/org/apache/http/protocol/HttpRequestHandlerRegistry.java b/src/org/apache/http/protocol/HttpRequestHandlerRegistry.java
new file mode 100644
index 0000000..668d748
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpRequestHandlerRegistry.java
@@ -0,0 +1,82 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestHandlerRegistry.java $
+ * $Revision: 630662 $
+ * $Date: 2008-02-24 11:40:51 -0800 (Sun, 24 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.util.Map;
+
+/**
+ * Maintains a map of HTTP request handlers keyed by a request URI pattern.
+ * {@link HttpRequestHandler} instances can be looked up by request URI
+ * using the {@link HttpRequestHandlerResolver} interface.<br/>
+ * Patterns may have three formats:
+ * <ul>
+ * <li><code>*</code></li>
+ * <li><code>*&lt;uri&gt;</code></li>
+ * <li><code>&lt;uri&gt;*</code></li>
+ * </ul>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 630662 $
+ */
+public class HttpRequestHandlerRegistry implements HttpRequestHandlerResolver {
+
+ private final UriPatternMatcher matcher;
+
+ public HttpRequestHandlerRegistry() {
+ matcher = new UriPatternMatcher();
+ }
+
+ public void register(final String pattern, final HttpRequestHandler handler) {
+ matcher.register(pattern, handler);
+ }
+
+ public void unregister(final String pattern) {
+ matcher.unregister(pattern);
+ }
+
+ public void setHandlers(final Map map) {
+ matcher.setHandlers(map);
+ }
+
+ public HttpRequestHandler lookup(final String requestURI) {
+ return (HttpRequestHandler) matcher.lookup(requestURI);
+ }
+
+ /**
+ * @deprecated
+ */
+ protected boolean matchUriRequestPattern(final String pattern, final String requestUri) {
+ return matcher.matchUriRequestPattern(pattern, requestUri);
+ }
+
+}
diff --git a/src/org/apache/http/protocol/HttpRequestHandlerResolver.java b/src/org/apache/http/protocol/HttpRequestHandlerResolver.java
new file mode 100644
index 0000000..be92deb
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpRequestHandlerResolver.java
@@ -0,0 +1,46 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestHandlerResolver.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+/**
+ * Interface to be implemented by objects that can resolve
+ * {@link HttpRequestHandler} instances by request URI.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 613298 $
+ */
+public interface HttpRequestHandlerResolver {
+
+ HttpRequestHandler lookup(String requestURI);
+
+}
diff --git a/src/org/apache/http/protocol/HttpRequestInterceptorList.java b/src/org/apache/http/protocol/HttpRequestInterceptorList.java
new file mode 100644
index 0000000..84ec761
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpRequestInterceptorList.java
@@ -0,0 +1,120 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestInterceptorList.java $
+ * $Revision: 554903 $
+ * $Date: 2007-07-10 03:54:17 -0700 (Tue, 10 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.util.List;
+
+import org.apache.http.HttpRequestInterceptor;
+
+/**
+ * Provides access to an ordered list of request interceptors.
+ * Lists are expected to be built upfront and used read-only afterwards
+ * for {@link HttpProcessor processing}.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 554903 $
+ *
+ * @since 4.0
+ */
+public interface HttpRequestInterceptorList {
+
+ /**
+ * Appends a request interceptor to this list.
+ *
+ * @param itcp the request interceptor to add
+ */
+ void addRequestInterceptor(HttpRequestInterceptor itcp)
+ ;
+
+
+ /**
+ * Inserts a request interceptor at the specified index.
+ *
+ * @param itcp the request interceptor to add
+ * @param index the index to insert the interceptor at
+ */
+ void addRequestInterceptor(HttpRequestInterceptor itcp, int index);
+
+
+ /**
+ * Obtains the current size of this list.
+ *
+ * @return the number of request interceptors in this list
+ */
+ int getRequestInterceptorCount()
+ ;
+
+
+ /**
+ * Obtains a request interceptor from this list.
+ *
+ * @param index the index of the interceptor to obtain,
+ * 0 for first
+ *
+ * @return the interceptor at the given index, or
+ * <code>null</code> if the index is out of range
+ */
+ HttpRequestInterceptor getRequestInterceptor(int index)
+ ;
+
+
+ /**
+ * Removes all request interceptors from this list.
+ */
+ void clearRequestInterceptors()
+ ;
+
+
+ /**
+ * Removes all request interceptor of the specified class
+ *
+ * @param clazz the class of the instances to be removed.
+ */
+ void removeRequestInterceptorByClass(Class clazz);
+
+
+ /**
+ * Sets the request interceptors in this list.
+ * This list will be cleared and re-initialized to contain
+ * all request interceptors from the argument list.
+ * If the argument list includes elements that are not request
+ * interceptors, the behavior is implementation dependent.
+ *
+ * @param itcps the list of request interceptors
+ */
+ void setInterceptors(List itcps)
+ ;
+
+
+} // interface HttpRequestInterceptorList
+
diff --git a/src/org/apache/http/protocol/HttpResponseInterceptorList.java b/src/org/apache/http/protocol/HttpResponseInterceptorList.java
new file mode 100644
index 0000000..8b5811b
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpResponseInterceptorList.java
@@ -0,0 +1,121 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpResponseInterceptorList.java $
+ * $Revision: 554903 $
+ * $Date: 2007-07-10 03:54:17 -0700 (Tue, 10 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+
+import java.util.List;
+
+import org.apache.http.HttpResponseInterceptor;
+
+
+/**
+ * Provides access to an ordered list of response interceptors.
+ * Lists are expected to be built upfront and used read-only afterwards
+ * for {@link HttpProcessor processing}.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ * @version $Revision: 554903 $
+ *
+ * @since 4.0
+ */
+public interface HttpResponseInterceptorList {
+
+ /**
+ * Appends a response interceptor to this list.
+ *
+ * @param itcp the response interceptor to add
+ */
+ void addResponseInterceptor(HttpResponseInterceptor itcp)
+ ;
+
+ /**
+ * Inserts a response interceptor at the specified index.
+ *
+ * @param itcp the response interceptor to add
+ * @param index the index to insert the interceptor at
+ */
+ void addResponseInterceptor(HttpResponseInterceptor itcp, int index);
+
+
+ /**
+ * Obtains the current size of this list.
+ *
+ * @return the number of response interceptors in this list
+ */
+ int getResponseInterceptorCount()
+ ;
+
+
+ /**
+ * Obtains a response interceptor from this list.
+ *
+ * @param index the index of the interceptor to obtain,
+ * 0 for first
+ *
+ * @return the interceptor at the given index, or
+ * <code>null</code> if the index is out of range
+ */
+ HttpResponseInterceptor getResponseInterceptor(int index)
+ ;
+
+
+ /**
+ * Removes all response interceptors from this list.
+ */
+ void clearResponseInterceptors()
+ ;
+
+
+ /**
+ * Removes all response interceptor of the specified class
+ *
+ * @param clazz the class of the instances to be removed.
+ */
+ void removeResponseInterceptorByClass(Class clazz);
+
+
+ /**
+ * Sets the response interceptors in this list.
+ * This list will be cleared and re-initialized to contain
+ * all response interceptors from the argument list.
+ * If the argument list includes elements that are not response
+ * interceptors, the behavior is implementation dependent.
+ *
+ * @param itcps the list of response interceptors
+ */
+ void setInterceptors(List itcps)
+ ;
+
+
+} // interface HttpResponseInterceptorList
+
diff --git a/src/org/apache/http/protocol/HttpService.java b/src/org/apache/http/protocol/HttpService.java
new file mode 100644
index 0000000..991e931
--- /dev/null
+++ b/src/org/apache/http/protocol/HttpService.java
@@ -0,0 +1,249 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpService.java $
+ * $Revision: 610763 $
+ * $Date: 2008-01-10 04:01:13 -0800 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.HttpServerConnection;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.MethodNotSupportedException;
+import org.apache.http.ProtocolException;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.UnsupportedHttpVersionException;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.DefaultedHttpParams;
+import org.apache.http.util.EncodingUtils;
+
+/**
+ * Minimalistic server-side implementation of an HTTP processor.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 610763 $
+ */
+public class HttpService {
+
+ private HttpParams params = null;
+ private HttpProcessor processor = null;
+ private HttpRequestHandlerResolver handlerResolver = null;
+ private ConnectionReuseStrategy connStrategy = null;
+ private HttpResponseFactory responseFactory = null;
+ private HttpExpectationVerifier expectationVerifier = null;
+
+ /**
+ * Create a new HTTP service.
+ *
+ * @param proc the processor to use on requests and responses
+ * @param connStrategy the connection reuse strategy
+ * @param responseFactory the response factory
+ */
+ public HttpService(
+ final HttpProcessor proc,
+ final ConnectionReuseStrategy connStrategy,
+ final HttpResponseFactory responseFactory) {
+ super();
+ setHttpProcessor(proc);
+ setConnReuseStrategy(connStrategy);
+ setResponseFactory(responseFactory);
+ }
+
+ public void setHttpProcessor(final HttpProcessor processor) {
+ if (processor == null) {
+ throw new IllegalArgumentException("HTTP processor may not be null.");
+ }
+ this.processor = processor;
+ }
+
+ public void setConnReuseStrategy(final ConnectionReuseStrategy connStrategy) {
+ if (connStrategy == null) {
+ throw new IllegalArgumentException("Connection reuse strategy may not be null");
+ }
+ this.connStrategy = connStrategy;
+ }
+
+ public void setResponseFactory(final HttpResponseFactory responseFactory) {
+ if (responseFactory == null) {
+ throw new IllegalArgumentException("Response factory may not be null");
+ }
+ this.responseFactory = responseFactory;
+ }
+
+ public void setHandlerResolver(final HttpRequestHandlerResolver handlerResolver) {
+ this.handlerResolver = handlerResolver;
+ }
+
+ public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
+ this.expectationVerifier = expectationVerifier;
+ }
+
+ public HttpParams getParams() {
+ return this.params;
+ }
+
+ public void setParams(final HttpParams params) {
+ this.params = params;
+ }
+
+ public void handleRequest(
+ final HttpServerConnection conn,
+ final HttpContext context) throws IOException, HttpException {
+
+ context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+
+ HttpResponse response = null;
+
+ try {
+
+ HttpRequest request = conn.receiveRequestHeader();
+ request.setParams(
+ new DefaultedHttpParams(request.getParams(), this.params));
+
+ ProtocolVersion ver =
+ request.getRequestLine().getProtocolVersion();
+ if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
+ // Downgrade protocol version if greater than HTTP/1.1
+ ver = HttpVersion.HTTP_1_1;
+ }
+
+ if (request instanceof HttpEntityEnclosingRequest) {
+
+ if (((HttpEntityEnclosingRequest) request).expectContinue()) {
+ response = this.responseFactory.newHttpResponse(ver,
+ HttpStatus.SC_CONTINUE, context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+
+ if (this.expectationVerifier != null) {
+ try {
+ this.expectationVerifier.verify(request, response, context);
+ } catch (HttpException ex) {
+ response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0,
+ HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+ handleException(ex, response);
+ }
+ }
+ if (response.getStatusLine().getStatusCode() < 200) {
+ // Send 1xx response indicating the server expections
+ // have been met
+ conn.sendResponseHeader(response);
+ conn.flush();
+ response = null;
+ conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
+ }
+ } else {
+ conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
+ }
+ }
+
+ if (response == null) {
+ response = this.responseFactory.newHttpResponse(ver, HttpStatus.SC_OK, context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+
+ context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+ context.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
+
+ this.processor.process(request, context);
+ doService(request, response, context);
+ }
+
+ // Make sure the request content is fully consumed
+ if (request instanceof HttpEntityEnclosingRequest) {
+ HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
+ if (entity != null) {
+ entity.consumeContent();
+ }
+ }
+
+ } catch (HttpException ex) {
+ response = this.responseFactory.newHttpResponse
+ (HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR,
+ context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+ handleException(ex, response);
+ }
+
+ this.processor.process(response, context);
+ conn.sendResponseHeader(response);
+ conn.sendResponseEntity(response);
+ conn.flush();
+
+ if (!this.connStrategy.keepAlive(response, context)) {
+ conn.close();
+ }
+ }
+
+ protected void handleException(final HttpException ex, final HttpResponse response) {
+ if (ex instanceof MethodNotSupportedException) {
+ response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
+ } else if (ex instanceof UnsupportedHttpVersionException) {
+ response.setStatusCode(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED);
+ } else if (ex instanceof ProtocolException) {
+ response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
+ } else {
+ response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+ }
+ byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
+ ByteArrayEntity entity = new ByteArrayEntity(msg);
+ entity.setContentType("text/plain; charset=US-ASCII");
+ response.setEntity(entity);
+ }
+
+ protected void doService(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+ HttpRequestHandler handler = null;
+ if (this.handlerResolver != null) {
+ String requestURI = request.getRequestLine().getUri();
+ handler = this.handlerResolver.lookup(requestURI);
+ }
+ if (handler != null) {
+ handler.handle(request, response, context);
+ } else {
+ response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/RequestConnControl.java b/src/org/apache/http/protocol/RequestConnControl.java
new file mode 100644
index 0000000..0a7088c
--- /dev/null
+++ b/src/org/apache/http/protocol/RequestConnControl.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/RequestConnControl.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+
+/**
+ * A request interceptor that suggests connection keep-alive to the server.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public class RequestConnControl implements HttpRequestInterceptor {
+
+ public RequestConnControl() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (!request.containsHeader(HTTP.CONN_DIRECTIVE)) {
+ // Default policy is to keep connection alive
+ // whenever possible
+ request.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/RequestContent.java b/src/org/apache/http/protocol/RequestContent.java
new file mode 100644
index 0000000..745f604
--- /dev/null
+++ b/src/org/apache/http/protocol/RequestContent.java
@@ -0,0 +1,101 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/RequestContent.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ProtocolException;
+
+/**
+ * A request interceptor that decides about the transport encoding.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class RequestContent implements HttpRequestInterceptor {
+
+ public RequestContent() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (request instanceof HttpEntityEnclosingRequest) {
+ if (request.containsHeader(HTTP.TRANSFER_ENCODING)) {
+ throw new ProtocolException("Transfer-encoding header already present");
+ }
+ if (request.containsHeader(HTTP.CONTENT_LEN)) {
+ throw new ProtocolException("Content-Length header already present");
+ }
+ ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
+ HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
+ if (entity == null) {
+ request.addHeader(HTTP.CONTENT_LEN, "0");
+ return;
+ }
+ // Must specify a transfer encoding or a content length
+ if (entity.isChunked() || entity.getContentLength() < 0) {
+ if (ver.lessEquals(HttpVersion.HTTP_1_0)) {
+ throw new ProtocolException(
+ "Chunked transfer encoding not allowed for " + ver);
+ }
+ request.addHeader(HTTP.TRANSFER_ENCODING, HTTP.CHUNK_CODING);
+ } else {
+ request.addHeader(HTTP.CONTENT_LEN, Long.toString(entity.getContentLength()));
+ }
+ // Specify a content type if known
+ if (entity.getContentType() != null && !request.containsHeader(
+ HTTP.CONTENT_TYPE )) {
+ request.addHeader(entity.getContentType());
+ }
+ // Specify a content encoding if known
+ if (entity.getContentEncoding() != null && !request.containsHeader(
+ HTTP.CONTENT_ENCODING)) {
+ request.addHeader(entity.getContentEncoding());
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/RequestDate.java b/src/org/apache/http/protocol/RequestDate.java
new file mode 100644
index 0000000..6462906
--- /dev/null
+++ b/src/org/apache/http/protocol/RequestDate.java
@@ -0,0 +1,72 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/RequestDate.java $
+ * $Revision: 555989 $
+ * $Date: 2007-07-13 06:33:39 -0700 (Fri, 13 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpRequestInterceptor;
+
+/**
+ * A request interceptor that adds a Date header.
+ * For use on the client side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 555989 $
+ *
+ * @since 4.0
+ */
+public class RequestDate implements HttpRequestInterceptor {
+
+ private static final HttpDateGenerator DATE_GENERATOR = new HttpDateGenerator();
+
+ public RequestDate() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException
+ ("HTTP request may not be null.");
+ }
+ if ((request instanceof HttpEntityEnclosingRequest) &&
+ !request.containsHeader(HTTP.DATE_HEADER)) {
+ String httpdate = DATE_GENERATOR.getCurrentDate();
+ request.setHeader(HTTP.DATE_HEADER, httpdate);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/RequestExpectContinue.java b/src/org/apache/http/protocol/RequestExpectContinue.java
new file mode 100644
index 0000000..0799849
--- /dev/null
+++ b/src/org/apache/http/protocol/RequestExpectContinue.java
@@ -0,0 +1,78 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/RequestExpectContinue.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.params.HttpProtocolParams;
+
+/**
+ * A request interceptor that enables the expect-continue handshake.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class RequestExpectContinue implements HttpRequestInterceptor {
+
+ public RequestExpectContinue() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (request instanceof HttpEntityEnclosingRequest) {
+ HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
+ // Do not send the expect header if request body is known to be empty
+ if (entity != null && entity.getContentLength() != 0) {
+ ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
+ if (HttpProtocolParams.useExpectContinue(request.getParams())
+ && !ver.lessEquals(HttpVersion.HTTP_1_0)) {
+ request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/RequestTargetHost.java b/src/org/apache/http/protocol/RequestTargetHost.java
new file mode 100644
index 0000000..9349a8a
--- /dev/null
+++ b/src/org/apache/http/protocol/RequestTargetHost.java
@@ -0,0 +1,98 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/RequestTargetHost.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import org.apache.http.HttpConnection;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpInetConnection;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ProtocolException;
+
+/**
+ * A request interceptor that sets the Host header for HTTP/1.1 requests.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class RequestTargetHost implements HttpRequestInterceptor {
+
+ public RequestTargetHost() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+ if (!request.containsHeader(HTTP.TARGET_HOST)) {
+ HttpHost targethost = (HttpHost) context
+ .getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+ if (targethost == null) {
+ HttpConnection conn = (HttpConnection) context
+ .getAttribute(ExecutionContext.HTTP_CONNECTION);
+ if (conn instanceof HttpInetConnection) {
+ // Populate the context with a default HTTP host based on the
+ // inet address of the target host
+ InetAddress address = ((HttpInetConnection) conn).getRemoteAddress();
+ int port = ((HttpInetConnection) conn).getRemotePort();
+ if (address != null) {
+ targethost = new HttpHost(address.getHostName(), port);
+ }
+ }
+ if (targethost == null) {
+ ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
+ if (ver.lessEquals(HttpVersion.HTTP_1_0)) {
+ return;
+ } else {
+ throw new ProtocolException("Target host missing");
+ }
+ }
+ }
+ request.addHeader(HTTP.TARGET_HOST, targethost.toHostString());
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/RequestUserAgent.java b/src/org/apache/http/protocol/RequestUserAgent.java
new file mode 100644
index 0000000..5a3145f
--- /dev/null
+++ b/src/org/apache/http/protocol/RequestUserAgent.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/RequestUserAgent.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.params.HttpProtocolParams;
+
+/**
+ * A request interceptor that adds a User-Agent header.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public class RequestUserAgent implements HttpRequestInterceptor {
+
+ public RequestUserAgent() {
+ super();
+ }
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (!request.containsHeader(HTTP.USER_AGENT)) {
+ String useragent = HttpProtocolParams.getUserAgent(request.getParams());
+ if (useragent != null) {
+ request.addHeader(HTTP.USER_AGENT, useragent);
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/ResponseConnControl.java b/src/org/apache/http/protocol/ResponseConnControl.java
new file mode 100644
index 0000000..2e535fe
--- /dev/null
+++ b/src/org/apache/http/protocol/ResponseConnControl.java
@@ -0,0 +1,104 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/ResponseConnControl.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+
+/**
+ * A response interceptor that suggests connection keep-alive to the client.
+ * For use on the server side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public class ResponseConnControl implements HttpResponseInterceptor {
+
+ public ResponseConnControl() {
+ super();
+ }
+
+ public void process(final HttpResponse response, final HttpContext context)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP response may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("HTTP context may not be null");
+ }
+ // Always drop connection after certain type of responses
+ int status = response.getStatusLine().getStatusCode();
+ if (status == HttpStatus.SC_BAD_REQUEST ||
+ status == HttpStatus.SC_REQUEST_TIMEOUT ||
+ status == HttpStatus.SC_LENGTH_REQUIRED ||
+ status == HttpStatus.SC_REQUEST_TOO_LONG ||
+ status == HttpStatus.SC_REQUEST_URI_TOO_LONG ||
+ status == HttpStatus.SC_SERVICE_UNAVAILABLE ||
+ status == HttpStatus.SC_NOT_IMPLEMENTED) {
+ response.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
+ return;
+ }
+ // Always drop connection for HTTP/1.0 responses and below
+ // if the content body cannot be correctly delimited
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
+ if (entity.getContentLength() < 0 &&
+ (!entity.isChunked() || ver.lessEquals(HttpVersion.HTTP_1_0))) {
+ response.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
+ return;
+ }
+ }
+ // Drop connection if requested by the client
+ HttpRequest request = (HttpRequest)
+ context.getAttribute(ExecutionContext.HTTP_REQUEST);
+ if (request != null) {
+ Header header = request.getFirstHeader(HTTP.CONN_DIRECTIVE);
+ if (header != null) {
+ response.setHeader(HTTP.CONN_DIRECTIVE, header.getValue());
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/ResponseContent.java b/src/org/apache/http/protocol/ResponseContent.java
new file mode 100644
index 0000000..d1ac054
--- /dev/null
+++ b/src/org/apache/http/protocol/ResponseContent.java
@@ -0,0 +1,101 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/ResponseContent.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ProtocolException;
+
+/**
+ * A response interceptor that sets up entity-related headers.
+ * For use on the server side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class ResponseContent implements HttpResponseInterceptor {
+
+ public ResponseContent() {
+ super();
+ }
+
+ public void process(final HttpResponse response, final HttpContext context)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (response.containsHeader(HTTP.TRANSFER_ENCODING)) {
+ throw new ProtocolException("Transfer-encoding header already present");
+ }
+ if (response.containsHeader(HTTP.CONTENT_LEN)) {
+ throw new ProtocolException("Content-Length header already present");
+ }
+ ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ long len = entity.getContentLength();
+ if (entity.isChunked() && !ver.lessEquals(HttpVersion.HTTP_1_0)) {
+ response.addHeader(HTTP.TRANSFER_ENCODING, HTTP.CHUNK_CODING);
+ } else if (len >= 0) {
+ response.addHeader(HTTP.CONTENT_LEN, Long.toString(entity.getContentLength()));
+ }
+ // Specify a content type if known
+ if (entity.getContentType() != null && !response.containsHeader(
+ HTTP.CONTENT_TYPE )) {
+ response.addHeader(entity.getContentType());
+ }
+ // Specify a content encoding if known
+ if (entity.getContentEncoding() != null && !response.containsHeader(
+ HTTP.CONTENT_ENCODING)) {
+ response.addHeader(entity.getContentEncoding());
+ }
+ } else {
+ int status = response.getStatusLine().getStatusCode();
+ if (status != HttpStatus.SC_NO_CONTENT
+ && status != HttpStatus.SC_NOT_MODIFIED
+ && status != HttpStatus.SC_RESET_CONTENT) {
+ response.addHeader(HTTP.CONTENT_LEN, "0");
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/ResponseDate.java b/src/org/apache/http/protocol/ResponseDate.java
new file mode 100644
index 0000000..431dc19
--- /dev/null
+++ b/src/org/apache/http/protocol/ResponseDate.java
@@ -0,0 +1,73 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/ResponseDate.java $
+ * $Revision: 555989 $
+ * $Date: 2007-07-13 06:33:39 -0700 (Fri, 13 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpStatus;
+
+/**
+ * A response interceptor that adds a Date header.
+ * For use on the server side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 555989 $
+ *
+ * @since 4.0
+ */
+public class ResponseDate implements HttpResponseInterceptor {
+
+ private static final HttpDateGenerator DATE_GENERATOR = new HttpDateGenerator();
+
+ public ResponseDate() {
+ super();
+ }
+
+ public void process(final HttpResponse response, final HttpContext context)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException
+ ("HTTP response may not be null.");
+ }
+ int status = response.getStatusLine().getStatusCode();
+ if ((status >= HttpStatus.SC_OK) &&
+ !response.containsHeader(HTTP.DATE_HEADER)) {
+ String httpdate = DATE_GENERATOR.getCurrentDate();
+ response.setHeader(HTTP.DATE_HEADER, httpdate);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/ResponseServer.java b/src/org/apache/http/protocol/ResponseServer.java
new file mode 100644
index 0000000..44df593
--- /dev/null
+++ b/src/org/apache/http/protocol/ResponseServer.java
@@ -0,0 +1,71 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/ResponseServer.java $
+ * $Revision: 576073 $
+ * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.params.CoreProtocolPNames;
+
+/**
+ * A response interceptor that adds a Server header.
+ * For use on the server side.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 576073 $
+ *
+ * @since 4.0
+ */
+public class ResponseServer implements HttpResponseInterceptor {
+
+ public ResponseServer() {
+ super();
+ }
+
+ public void process(final HttpResponse response, final HttpContext context)
+ throws HttpException, IOException {
+ if (response == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (!response.containsHeader(HTTP.SERVER_HEADER)) {
+ String s = (String) response.getParams().getParameter(
+ CoreProtocolPNames.ORIGIN_SERVER);
+ if (s != null) {
+ response.addHeader(HTTP.SERVER_HEADER, s);
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/SyncBasicHttpContext.java b/src/org/apache/http/protocol/SyncBasicHttpContext.java
new file mode 100644
index 0000000..b1a408b
--- /dev/null
+++ b/src/org/apache/http/protocol/SyncBasicHttpContext.java
@@ -0,0 +1,61 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/SyncBasicHttpContext.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 14:09:22 -0800 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+/**
+ * Thread-safe extension of the {@link BasicHttpContext}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 613298 $
+ *
+ * @since 4.0
+ */
+public class SyncBasicHttpContext extends BasicHttpContext {
+
+ public SyncBasicHttpContext(final HttpContext parentContext) {
+ super(parentContext);
+ }
+
+ public synchronized Object getAttribute(final String id) {
+ return super.getAttribute(id);
+ }
+
+ public synchronized void setAttribute(final String id, final Object obj) {
+ super.setAttribute(id, obj);
+ }
+
+ public synchronized Object removeAttribute(final String id) {
+ return super.removeAttribute(id);
+ }
+
+}
diff --git a/src/org/apache/http/protocol/UriPatternMatcher.java b/src/org/apache/http/protocol/UriPatternMatcher.java
new file mode 100644
index 0000000..2870d99
--- /dev/null
+++ b/src/org/apache/http/protocol/UriPatternMatcher.java
@@ -0,0 +1,127 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/UriPatternMatcher.java $
+ * $Revision: 630662 $
+ * $Date: 2008-02-24 11:40:51 -0800 (Sun, 24 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.protocol;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Maintains a map of objects keyed by a request URI pattern.
+ * Instances can be looked up by request URI.<br/>
+ * Patterns may have three formats:
+ * <ul>
+ * <li><code>*</code></li>
+ * <li><code>*&lt;uri&gt;</code></li>
+ * <li><code>&lt;uri&gt;*</code></li>
+ * </ul>
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 630662 $
+ */
+public class UriPatternMatcher {
+
+ private final Map handlerMap;
+
+ public UriPatternMatcher() {
+ super();
+ this.handlerMap = new HashMap();
+ }
+
+ public void register(final String pattern, final Object handler) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("URI request pattern may not be null");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("HTTP request handelr may not be null");
+ }
+ this.handlerMap.put(pattern, handler);
+ }
+
+ public void unregister(final String pattern) {
+ if (pattern == null) {
+ return;
+ }
+ this.handlerMap.remove(pattern);
+ }
+
+ public void setHandlers(final Map map) {
+ if (map == null) {
+ throw new IllegalArgumentException("Map of handlers may not be null");
+ }
+ this.handlerMap.clear();
+ this.handlerMap.putAll(map);
+ }
+
+ public Object lookup(String requestURI) {
+ if (requestURI == null) {
+ throw new IllegalArgumentException("Request URI may not be null");
+ }
+ //Strip away the query part part if found
+ int index = requestURI.indexOf("?");
+ if (index != -1) {
+ requestURI = requestURI.substring(0, index);
+ }
+
+ // direct match?
+ Object handler = this.handlerMap.get(requestURI);
+ if (handler == null) {
+ // pattern match?
+ String bestMatch = null;
+ for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
+ String pattern = (String) it.next();
+ if (matchUriRequestPattern(pattern, requestURI)) {
+ // we have a match. is it any better?
+ if (bestMatch == null
+ || (bestMatch.length() < pattern.length())
+ || (bestMatch.length() == pattern.length() && pattern.endsWith("*"))) {
+ handler = this.handlerMap.get(pattern);
+ bestMatch = pattern;
+ }
+ }
+ }
+ }
+ return handler;
+ }
+
+ protected boolean matchUriRequestPattern(final String pattern, final String requestUri) {
+ if (pattern.equals("*")) {
+ return true;
+ } else {
+ return
+ (pattern.endsWith("*") && requestUri.startsWith(pattern.substring(0, pattern.length() - 1))) ||
+ (pattern.startsWith("*") && requestUri.endsWith(pattern.substring(1, pattern.length())));
+ }
+ }
+
+}
diff --git a/src/org/apache/http/protocol/package.html b/src/org/apache/http/protocol/package.html
new file mode 100644
index 0000000..5056bcc
--- /dev/null
+++ b/src/org/apache/http/protocol/package.html
@@ -0,0 +1,112 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/package.html $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+HTTP protocol execution framework.
+
+Apart from simply sending and receiving messages, there are a lot
+of things to consider when communicating with HTTP. Many details
+such as transport encodings or connection management are handled
+by setting up or interpreting
+{@link org.apache.http.Header headers} in the messages.
+In order to relieve applications from the responsibility of
+implementing these nitty-gritty details of the protocol,
+HTTP components provides an execution framework that sets up
+some of the headers before sending a message, and interprets
+headers when a message has been received.
+<br/>
+An HTTP {@link org.apache.http.protocol.HttpProcessor processor}
+typically keeps lists of so-called interceptors that will be executed
+before a message is sent and after it has been received.
+An application should initialize a processor, set up the lists
+with the required and desired processors, and then communicate
+through that processor. There are four kinds of interceptors,
+depending on whether they act on
+{@link org.apache.http.HttpRequestInterceptor requests} or
+{@link org.apache.http.HttpResponseInterceptor responses},
+on the client or server side:
+
+<table border="1" cellpadding="5">
+<tr><th></th>
+ <th>Client</th>
+ <th>Server</th>
+</tr>
+<tr><th>Request</th>
+ <td>prepares headers before a request is sent</td>
+ <td>interprets headers when a request is received</td>
+</tr>
+<tr><th>Response</th>
+ <td>interprets headers when a response is received</td>
+ <td>prepares headers before a response is sent</td>
+</tr>
+</table>
+
+<p>
+{@link org.apache.http.protocol.HttpRequestExecutor HttpRequestExecutor}
+is a processor for the client side,
+{@link org.apache.http.protocol.HttpService HttpService}
+for the server side.
+On the client side, a {@link org.apache.http.protocol.HttpContext context}
+is used to tie together a request, the response to it, and other data
+that might be associated with the request execution. It is passed to
+the request executor whenever needed.
+</p>
+
+<p>
+<font size="+1">
+<i>
+Information about required and recommended interceptors for the
+client side will be provided elsewhere. For the time being, please
+refer to the comments in the example applications or ask on
+one of the mailing lists.
+</i>
+</font>
+</p>
+
+<p>
+<b>Note:</b>
+If you want to develop a server-side application, we recommend that
+you implement your application as a servlet running in a servlet engine
+like <a href="http://tomcat.apache.org/">Tomcat</a> or full-blown
+JSEE container like <a href="http://geronimo.apache.org/">Geronimo</a>.
+If you prefer to implement a server-side application based on our
+{@link org.apache.http.protocol.HttpService HttpService}, we'll
+assume that you know what you're doing and that you don't need
+help in figuring out which interceptors need to be configured.
+</p>
+
+
+</body>
+</html>
diff --git a/src/org/apache/http/svn.info b/src/org/apache/http/svn.info
new file mode 100644
index 0000000..100deb5
--- /dev/null
+++ b/src/org/apache/http/svn.info
@@ -0,0 +1,8 @@
+Repository Root: http://svn.apache.org/repos/asf
+Repository UUID: 13f79535-47bb-0310-9956-ffa450edef68
+Revision: 677354
+Node Kind: directory
+Schedule: normal
+Last Changed Author: olegk
+Last Changed Rev: 677250
+Last Changed Date: 2008-07-16 04:45:47 -0700 (Wed, 16 Jul 2008)
diff --git a/src/org/apache/http/util/ByteArrayBuffer.java b/src/org/apache/http/util/ByteArrayBuffer.java
new file mode 100644
index 0000000..01d6577
--- /dev/null
+++ b/src/org/apache/http/util/ByteArrayBuffer.java
@@ -0,0 +1,162 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/ByteArrayBuffer.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.util;
+
+/**
+ * A resizable byte array.
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public final class ByteArrayBuffer {
+
+ private byte[] buffer;
+ private int len;
+
+ public ByteArrayBuffer(int capacity) {
+ super();
+ if (capacity < 0) {
+ throw new IllegalArgumentException("Buffer capacity may not be negative");
+ }
+ this.buffer = new byte[capacity];
+ }
+
+ private void expand(int newlen) {
+ byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
+ System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
+ this.buffer = newbuffer;
+ }
+
+ public void append(final byte[] b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) < 0) || ((off + len) > b.length)) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (len == 0) {
+ return;
+ }
+ int newlen = this.len + len;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ System.arraycopy(b, off, this.buffer, this.len, len);
+ this.len = newlen;
+ }
+
+ public void append(int b) {
+ int newlen = this.len + 1;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ this.buffer[this.len] = (byte)b;
+ this.len = newlen;
+ }
+
+ public void append(final char[] b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) < 0) || ((off + len) > b.length)) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (len == 0) {
+ return;
+ }
+ int oldlen = this.len;
+ int newlen = oldlen + len;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
+ this.buffer[i2] = (byte) b[i1];
+ }
+ this.len = newlen;
+ }
+
+ public void append(final CharArrayBuffer b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ append(b.buffer(), off, len);
+ }
+
+ public void clear() {
+ this.len = 0;
+ }
+
+ public byte[] toByteArray() {
+ byte[] b = new byte[this.len];
+ if (this.len > 0) {
+ System.arraycopy(this.buffer, 0, b, 0, this.len);
+ }
+ return b;
+ }
+
+ public int byteAt(int i) {
+ return this.buffer[i];
+ }
+
+ public int capacity() {
+ return this.buffer.length;
+ }
+
+ public int length() {
+ return this.len;
+ }
+
+ public byte[] buffer() {
+ return this.buffer;
+ }
+
+ public void setLength(int len) {
+ if (len < 0 || len > this.buffer.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ this.len = len;
+ }
+
+ public boolean isEmpty() {
+ return this.len == 0;
+ }
+
+ public boolean isFull() {
+ return this.len == this.buffer.length;
+ }
+
+}
diff --git a/src/org/apache/http/util/CharArrayBuffer.java b/src/org/apache/http/util/CharArrayBuffer.java
new file mode 100644
index 0000000..b89f5d1
--- /dev/null
+++ b/src/org/apache/http/util/CharArrayBuffer.java
@@ -0,0 +1,264 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/CharArrayBuffer.java $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.util;
+
+import org.apache.http.protocol.HTTP;
+
+/**
+ * A resizable char array.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 496070 $
+ *
+ * @since 4.0
+ */
+public final class CharArrayBuffer {
+
+ private char[] buffer;
+ private int len;
+
+ public CharArrayBuffer(int capacity) {
+ super();
+ if (capacity < 0) {
+ throw new IllegalArgumentException("Buffer capacity may not be negative");
+ }
+ this.buffer = new char[capacity];
+ }
+
+ private void expand(int newlen) {
+ char newbuffer[] = new char[Math.max(this.buffer.length << 1, newlen)];
+ System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
+ this.buffer = newbuffer;
+ }
+
+ public void append(final char[] b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) < 0) || ((off + len) > b.length)) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (len == 0) {
+ return;
+ }
+ int newlen = this.len + len;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ System.arraycopy(b, off, this.buffer, this.len, len);
+ this.len = newlen;
+ }
+
+ public void append(String str) {
+ if (str == null) {
+ str = "null";
+ }
+ int strlen = str.length();
+ int newlen = this.len + strlen;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ str.getChars(0, strlen, this.buffer, this.len);
+ this.len = newlen;
+ }
+
+ public void append(final CharArrayBuffer b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ append(b.buffer, off, len);
+ }
+
+ public void append(final CharArrayBuffer b) {
+ if (b == null) {
+ return;
+ }
+ append(b.buffer,0, b.len);
+ }
+
+ public void append(char ch) {
+ int newlen = this.len + 1;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ this.buffer[this.len] = ch;
+ this.len = newlen;
+ }
+
+ public void append(final byte[] b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) < 0) || ((off + len) > b.length)) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (len == 0) {
+ return;
+ }
+ int oldlen = this.len;
+ int newlen = oldlen + len;
+ if (newlen > this.buffer.length) {
+ expand(newlen);
+ }
+ for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
+ int ch = b[i1];
+ if (ch < 0) {
+ ch = 256 + ch;
+ }
+ this.buffer[i2] = (char) ch;
+ }
+ this.len = newlen;
+ }
+
+ public void append(final ByteArrayBuffer b, int off, int len) {
+ if (b == null) {
+ return;
+ }
+ append(b.buffer(), off, len);
+ }
+
+ public void append(final Object obj) {
+ append(String.valueOf(obj));
+ }
+
+ public void clear() {
+ this.len = 0;
+ }
+
+ public char[] toCharArray() {
+ char[] b = new char[this.len];
+ if (this.len > 0) {
+ System.arraycopy(this.buffer, 0, b, 0, this.len);
+ }
+ return b;
+ }
+
+ public char charAt(int i) {
+ return this.buffer[i];
+ }
+
+ public char[] buffer() {
+ return this.buffer;
+ }
+
+ public int capacity() {
+ return this.buffer.length;
+ }
+
+ public int length() {
+ return this.len;
+ }
+
+ public void ensureCapacity(int required) {
+ int available = this.buffer.length - this.len;
+ if (required > available) {
+ expand(this.len + required);
+ }
+ }
+
+ public void setLength(int len) {
+ if (len < 0 || len > this.buffer.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ this.len = len;
+ }
+
+ public boolean isEmpty() {
+ return this.len == 0;
+ }
+
+ public boolean isFull() {
+ return this.len == this.buffer.length;
+ }
+
+ public int indexOf(int ch, int beginIndex, int endIndex) {
+ if (beginIndex < 0) {
+ beginIndex = 0;
+ }
+ if (endIndex > this.len) {
+ endIndex = this.len;
+ }
+ if (beginIndex > endIndex) {
+ return -1;
+ }
+ for (int i = beginIndex; i < endIndex; i++) {
+ if (this.buffer[i] == ch) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int indexOf(int ch) {
+ return indexOf(ch, 0, this.len);
+ }
+
+ public String substring(int beginIndex, int endIndex) {
+ if (beginIndex < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (endIndex > this.len) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (beginIndex > endIndex) {
+ throw new IndexOutOfBoundsException();
+ }
+ return new String(this.buffer, beginIndex, endIndex - beginIndex);
+ }
+
+ public String substringTrimmed(int beginIndex, int endIndex) {
+ if (beginIndex < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (endIndex > this.len) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (beginIndex > endIndex) {
+ throw new IndexOutOfBoundsException();
+ }
+ while (beginIndex < endIndex && HTTP.isWhitespace(this.buffer[beginIndex])) {
+ beginIndex++;
+ }
+ while (endIndex > beginIndex && HTTP.isWhitespace(this.buffer[endIndex - 1])) {
+ endIndex--;
+ }
+ return new String(this.buffer, beginIndex, endIndex - beginIndex);
+ }
+
+ public String toString() {
+ return new String(this.buffer, 0, this.len);
+ }
+
+}
diff --git a/src/org/apache/http/util/EncodingUtils.java b/src/org/apache/http/util/EncodingUtils.java
new file mode 100644
index 0000000..a1b3f44
--- /dev/null
+++ b/src/org/apache/http/util/EncodingUtils.java
@@ -0,0 +1,185 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/EncodingUtils.java $
+ * $Revision: 503413 $
+ * $Date: 2007-02-04 06:22:14 -0800 (Sun, 04 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.util;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.http.protocol.HTTP;
+
+/**
+ * The home for utility methods that handle various encoding tasks.
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public final class EncodingUtils {
+
+ /**
+ * Converts the byte array of HTTP content characters to a string. If
+ * the specified charset is not supported, default system encoding
+ * is used.
+ *
+ * @param data the byte array to be encoded
+ * @param offset the index of the first byte to encode
+ * @param length the number of bytes to encode
+ * @param charset the desired character encoding
+ * @return The result of the conversion.
+ */
+ public static String getString(
+ final byte[] data,
+ int offset,
+ int length,
+ String charset
+ ) {
+
+ if (data == null) {
+ throw new IllegalArgumentException("Parameter may not be null");
+ }
+
+ if (charset == null || charset.length() == 0) {
+ throw new IllegalArgumentException("charset may not be null or empty");
+ }
+
+ try {
+ return new String(data, offset, length, charset);
+ } catch (UnsupportedEncodingException e) {
+ return new String(data, offset, length);
+ }
+ }
+
+
+ /**
+ * Converts the byte array of HTTP content characters to a string. If
+ * the specified charset is not supported, default system encoding
+ * is used.
+ *
+ * @param data the byte array to be encoded
+ * @param charset the desired character encoding
+ * @return The result of the conversion.
+ */
+ public static String getString(final byte[] data, final String charset) {
+ if (data == null) {
+ throw new IllegalArgumentException("Parameter may not be null");
+ }
+ return getString(data, 0, data.length, charset);
+ }
+
+ /**
+ * Converts the specified string to a byte array. If the charset is not supported the
+ * default system charset is used.
+ *
+ * @param data the string to be encoded
+ * @param charset the desired character encoding
+ * @return The resulting byte array.
+ */
+ public static byte[] getBytes(final String data, final String charset) {
+
+ if (data == null) {
+ throw new IllegalArgumentException("data may not be null");
+ }
+
+ if (charset == null || charset.length() == 0) {
+ throw new IllegalArgumentException("charset may not be null or empty");
+ }
+
+ try {
+ return data.getBytes(charset);
+ } catch (UnsupportedEncodingException e) {
+ return data.getBytes();
+ }
+ }
+
+ /**
+ * Converts the specified string to byte array of ASCII characters.
+ *
+ * @param data the string to be encoded
+ * @return The string as a byte array.
+ */
+ public static byte[] getAsciiBytes(final String data) {
+
+ if (data == null) {
+ throw new IllegalArgumentException("Parameter may not be null");
+ }
+
+ try {
+ return data.getBytes(HTTP.US_ASCII);
+ } catch (UnsupportedEncodingException e) {
+ throw new Error("HttpClient requires ASCII support");
+ }
+ }
+
+ /**
+ * Converts the byte array of ASCII characters to a string. This method is
+ * to be used when decoding content of HTTP elements (such as response
+ * headers)
+ *
+ * @param data the byte array to be encoded
+ * @param offset the index of the first byte to encode
+ * @param length the number of bytes to encode
+ * @return The string representation of the byte array
+ */
+ public static String getAsciiString(final byte[] data, int offset, int length) {
+
+ if (data == null) {
+ throw new IllegalArgumentException("Parameter may not be null");
+ }
+
+ try {
+ return new String(data, offset, length, HTTP.US_ASCII);
+ } catch (UnsupportedEncodingException e) {
+ throw new Error("HttpClient requires ASCII support");
+ }
+ }
+
+ /**
+ * Converts the byte array of ASCII characters to a string. This method is
+ * to be used when decoding content of HTTP elements (such as response
+ * headers)
+ *
+ * @param data the byte array to be encoded
+ * @return The string representation of the byte array
+ */
+ public static String getAsciiString(final byte[] data) {
+ if (data == null) {
+ throw new IllegalArgumentException("Parameter may not be null");
+ }
+ return getAsciiString(data, 0, data.length);
+ }
+
+ /**
+ * This class should not be instantiated.
+ */
+ private EncodingUtils() {
+ }
+
+}
diff --git a/src/org/apache/http/util/EntityUtils.java b/src/org/apache/http/util/EntityUtils.java
new file mode 100644
index 0000000..f9a7cf3
--- /dev/null
+++ b/src/org/apache/http/util/EntityUtils.java
@@ -0,0 +1,149 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/EntityUtils.java $
+ * $Revision: 569637 $
+ * $Date: 2007-08-25 00:36:59 -0700 (Sat, 25 Aug 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Static helpers for dealing with {@link HttpEntity entities}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 569637 $
+ *
+ * @since 4.0
+ */
+public final class EntityUtils {
+
+ /** Disabled default constructor. */
+ private EntityUtils() {
+ }
+
+ public static byte[] toByteArray(final HttpEntity entity) throws IOException {
+ if (entity == null) {
+ throw new IllegalArgumentException("HTTP entity may not be null");
+ }
+ InputStream instream = entity.getContent();
+ if (instream == null) {
+ return new byte[] {};
+ }
+ if (entity.getContentLength() > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
+ }
+ int i = (int)entity.getContentLength();
+ if (i < 0) {
+ i = 4096;
+ }
+ ByteArrayBuffer buffer = new ByteArrayBuffer(i);
+ try {
+ byte[] tmp = new byte[4096];
+ int l;
+ while((l = instream.read(tmp)) != -1) {
+ buffer.append(tmp, 0, l);
+ }
+ } finally {
+ instream.close();
+ }
+ return buffer.toByteArray();
+ }
+
+ public static String getContentCharSet(final HttpEntity entity)
+ throws ParseException {
+
+ if (entity == null) {
+ throw new IllegalArgumentException("HTTP entity may not be null");
+ }
+ String charset = null;
+ if (entity.getContentType() != null) {
+ HeaderElement values[] = entity.getContentType().getElements();
+ if (values.length > 0) {
+ NameValuePair param = values[0].getParameterByName("charset");
+ if (param != null) {
+ charset = param.getValue();
+ }
+ }
+ }
+ return charset;
+ }
+
+ public static String toString(
+ final HttpEntity entity, final String defaultCharset) throws IOException, ParseException {
+ if (entity == null) {
+ throw new IllegalArgumentException("HTTP entity may not be null");
+ }
+ InputStream instream = entity.getContent();
+ if (instream == null) {
+ return "";
+ }
+ if (entity.getContentLength() > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
+ }
+ int i = (int)entity.getContentLength();
+ if (i < 0) {
+ i = 4096;
+ }
+ String charset = getContentCharSet(entity);
+ if (charset == null) {
+ charset = defaultCharset;
+ }
+ if (charset == null) {
+ charset = HTTP.DEFAULT_CONTENT_CHARSET;
+ }
+ Reader reader = new InputStreamReader(instream, charset);
+ CharArrayBuffer buffer = new CharArrayBuffer(i);
+ try {
+ char[] tmp = new char[1024];
+ int l;
+ while((l = reader.read(tmp)) != -1) {
+ buffer.append(tmp, 0, l);
+ }
+ } finally {
+ reader.close();
+ }
+ return buffer.toString();
+ }
+
+ public static String toString(final HttpEntity entity)
+ throws IOException, ParseException {
+ return toString(entity, null);
+ }
+
+}
diff --git a/src/org/apache/http/util/ExceptionUtils.java b/src/org/apache/http/util/ExceptionUtils.java
new file mode 100644
index 0000000..c7fdccd
--- /dev/null
+++ b/src/org/apache/http/util/ExceptionUtils.java
@@ -0,0 +1,85 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/ExceptionUtils.java $
+ * $Revision: 613003 $
+ * $Date: 2008-01-17 15:00:42 -0800 (Thu, 17 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.util;
+
+import java.lang.reflect.Method;
+
+/**
+ * The home for utility methods that handle various exception-related tasks.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
+ *
+ * @since 4.0
+ */
+public final class ExceptionUtils {
+
+ /** A reference to Throwable's initCause method, or null if it's not there in this JVM */
+ static private final Method INIT_CAUSE_METHOD = getInitCauseMethod();
+
+ /**
+ * Returns a <code>Method<code> allowing access to
+ * {@link Throwable#initCause(Throwable) initCause} method of {@link Throwable},
+ * or <code>null</code> if the method
+ * does not exist.
+ *
+ * @return A <code>Method<code> for <code>Throwable.initCause</code>, or
+ * <code>null</code> if unavailable.
+ */
+ static private Method getInitCauseMethod() {
+ try {
+ Class[] paramsClasses = new Class[] { Throwable.class };
+ return Throwable.class.getMethod("initCause", paramsClasses);
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ }
+
+ /**
+ * If we're running on JDK 1.4 or later, initialize the cause for the given throwable.
+ *
+ * @param throwable The throwable.
+ * @param cause The cause of the throwable.
+ */
+ public static void initCause(Throwable throwable, Throwable cause) {
+ if (INIT_CAUSE_METHOD != null) {
+ try {
+ INIT_CAUSE_METHOD.invoke(throwable, new Object[] { cause });
+ } catch (Exception e) {
+ // Well, with no logging, the only option is to munch the exception
+ }
+ }
+ }
+
+ private ExceptionUtils() {
+ }
+
+}
diff --git a/src/org/apache/http/util/LangUtils.java b/src/org/apache/http/util/LangUtils.java
new file mode 100644
index 0000000..a1dee8f
--- /dev/null
+++ b/src/org/apache/http/util/LangUtils.java
@@ -0,0 +1,88 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/LangUtils.java $
+ * $Revision: 503413 $
+ * $Date: 2007-02-04 06:22:14 -0800 (Sun, 04 Feb 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.util;
+
+/**
+ * A set of utility methods to help produce consistent
+ * {@link Object#equals equals} and {@link Object#hashCode hashCode} methods.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public final class LangUtils {
+
+ public static final int HASH_SEED = 17;
+ public static final int HASH_OFFSET = 37;
+
+ /** Disabled default constructor. */
+ private LangUtils() {
+ }
+
+ public static int hashCode(final int seed, final int hashcode) {
+ return seed * HASH_OFFSET + hashcode;
+ }
+
+ public static int hashCode(final int seed, final boolean b) {
+ return hashCode(seed, b ? 1 : 0);
+ }
+
+ public static int hashCode(final int seed, final Object obj) {
+ return hashCode(seed, obj != null ? obj.hashCode() : 0);
+ }
+
+ public static boolean equals(final Object obj1, final Object obj2) {
+ return obj1 == null ? obj2 == null : obj1.equals(obj2);
+ }
+
+ public static boolean equals(final Object[] a1, final Object[] a2) {
+ if (a1 == null) {
+ if (a2 == null) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if (a2 != null && a1.length == a2.length) {
+ for (int i = 0; i < a1.length; i++) {
+ if (!equals(a1[i], a2[i])) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+}
diff --git a/src/org/apache/http/util/VersionInfo.java b/src/org/apache/http/util/VersionInfo.java
new file mode 100644
index 0000000..0c95594
--- /dev/null
+++ b/src/org/apache/http/util/VersionInfo.java
@@ -0,0 +1,317 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/VersionInfo.java $
+ * $Revision: 554888 $
+ * $Date: 2007-07-10 02:46:36 -0700 (Tue, 10 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ArrayList;
+
+
+/**
+ * Provides access to version information for HTTP components.
+ * Instances of this class provide version information for a single module
+ * or informal unit, as explained
+ * <a href="http://wiki.apache.org/jakarta-httpclient/HttpComponents">here</a>.
+ * Static methods are used to extract version information from property
+ * files that are automatically packaged with HTTP component release JARs.
+ * <br/>
+ * All available version information is provided in strings, where
+ * the string format is informal and subject to change without notice.
+ * Version information is provided for debugging output and interpretation
+ * by humans, not for automated processing in applications.
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ * @author and others
+ */
+public class VersionInfo {
+
+ /** A string constant for unavailable information. */
+ public final static String UNAVAILABLE = "UNAVAILABLE";
+
+ /** The filename of the version information files. */
+ public final static String VERSION_PROPERTY_FILE = "version.properties";
+
+ // the property names
+ public final static String PROPERTY_MODULE = "info.module";
+ public final static String PROPERTY_RELEASE = "info.release";
+ public final static String PROPERTY_TIMESTAMP = "info.timestamp";
+
+
+ /** The package that contains the version information. */
+ private final String infoPackage;
+
+ /** The module from the version info. */
+ private final String infoModule;
+
+ /** The release from the version info. */
+ private final String infoRelease;
+
+ /** The timestamp from the version info. */
+ private final String infoTimestamp;
+
+ /** The classloader from which the version info was obtained. */
+ private final String infoClassloader;
+
+
+ /**
+ * Instantiates version information.
+ *
+ * @param pckg the package
+ * @param module the module, or <code>null</code>
+ * @param release the release, or <code>null</code>
+ * @param time the build time, or <code>null</code>
+ * @param clsldr the class loader, or <code>null</code>
+ */
+ protected VersionInfo(String pckg, String module,
+ String release, String time, String clsldr) {
+ if (pckg == null) {
+ throw new IllegalArgumentException
+ ("Package identifier must not be null.");
+ }
+
+ infoPackage = pckg;
+ infoModule = (module != null) ? module : UNAVAILABLE;
+ infoRelease = (release != null) ? release : UNAVAILABLE;
+ infoTimestamp = (time != null) ? time : UNAVAILABLE;
+ infoClassloader = (clsldr != null) ? clsldr : UNAVAILABLE;
+ }
+
+
+ /**
+ * Obtains the package name.
+ * The package name identifies the module or informal unit.
+ *
+ * @return the package name, never <code>null</code>
+ */
+ public final String getPackage() {
+ return infoPackage;
+ }
+
+ /**
+ * Obtains the name of the versioned module or informal unit.
+ * This data is read from the version information for the package.
+ *
+ * @return the module name, never <code>null</code>
+ */
+ public final String getModule() {
+ return infoModule;
+ }
+
+ /**
+ * Obtains the release of the versioned module or informal unit.
+ * This data is read from the version information for the package.
+ *
+ * @return the release version, never <code>null</code>
+ */
+ public final String getRelease() {
+ return infoRelease;
+ }
+
+ /**
+ * Obtains the timestamp of the versioned module or informal unit.
+ * This data is read from the version information for the package.
+ *
+ * @return the timestamp, never <code>null</code>
+ */
+ public final String getTimestamp() {
+ return infoTimestamp;
+ }
+
+ /**
+ * Obtains the classloader used to read the version information.
+ * This is just the <code>toString</code> output of the classloader,
+ * since the version information should not keep a reference to
+ * the classloader itself. That could prevent garbage collection.
+ *
+ * @return the classloader description, never <code>null</code>
+ */
+ public final String getClassloader() {
+ return infoClassloader;
+ }
+
+
+ /**
+ * Provides the version information in human-readable format.
+ *
+ * @return a string holding this version information
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer
+ (20 + infoPackage.length() + infoModule.length() +
+ infoRelease.length() + infoTimestamp.length() +
+ infoClassloader.length());
+
+ sb.append("VersionInfo(")
+ .append(infoPackage).append(':').append(infoModule);
+
+ // If version info is missing, a single "UNAVAILABLE" for the module
+ // is sufficient. Everything else just clutters the output.
+ if (!UNAVAILABLE.equals(infoRelease))
+ sb.append(':').append(infoRelease);
+ if (!UNAVAILABLE.equals(infoTimestamp))
+ sb.append(':').append(infoTimestamp);
+
+ sb.append(')');
+
+ if (!UNAVAILABLE.equals(infoClassloader))
+ sb.append('@').append(infoClassloader);
+
+ return sb.toString();
+ }
+
+
+ /**
+ * Loads version information for a list of packages.
+ *
+ * @param pckgs the packages for which to load version info
+ * @param clsldr the classloader to load from, or
+ * <code>null</code> for the thread context classloader
+ *
+ * @return the version information for all packages found,
+ * never <code>null</code>
+ */
+ public final static VersionInfo[] loadVersionInfo(String[] pckgs,
+ ClassLoader clsldr) {
+ if (pckgs == null) {
+ throw new IllegalArgumentException
+ ("Package identifier list must not be null.");
+ }
+
+ ArrayList vil = new ArrayList(pckgs.length);
+ for (int i=0; i<pckgs.length; i++) {
+ VersionInfo vi = loadVersionInfo(pckgs[i], clsldr);
+ if (vi != null)
+ vil.add(vi);
+ }
+
+ return (VersionInfo[]) vil.toArray(new VersionInfo[vil.size()]);
+ }
+
+
+ /**
+ * Loads version information for a package.
+ *
+ * @param pckg the package for which to load version information,
+ * for example "org.apache.http".
+ * The package name should NOT end with a dot.
+ * @param clsldr the classloader to load from, or
+ * <code>null</code> for the thread context classloader
+ *
+ * @return the version information for the argument package, or
+ * <code>null</code> if not available
+ */
+ public final static VersionInfo loadVersionInfo(final String pckg,
+ ClassLoader clsldr) {
+ if (pckg == null) {
+ throw new IllegalArgumentException
+ ("Package identifier must not be null.");
+ }
+
+ if (clsldr == null)
+ clsldr = Thread.currentThread().getContextClassLoader();
+
+ Properties vip = null; // version info properties, if available
+ try {
+ // org.apache.http becomes
+ // org/apache/http/version.properties
+ InputStream is = clsldr.getResourceAsStream
+ (pckg.replace('.', '/') + "/" + VERSION_PROPERTY_FILE);
+ if (is != null) {
+ try {
+ Properties props = new Properties();
+ props.load(is);
+ vip = props;
+ } finally {
+ is.close();
+ }
+ }
+ } catch (IOException ex) {
+ // shamelessly munch this exception
+ }
+
+ VersionInfo result = null;
+ if (vip != null)
+ result = fromMap(pckg, vip, clsldr);
+
+ return result;
+ }
+
+
+ /**
+ * Instantiates version information from properties.
+ *
+ * @param pckg the package for the version information
+ * @param info the map from string keys to string values,
+ * for example {@link java.util.Properties}
+ * @param clsldr the classloader, or <code>null</code>
+ *
+ * @return the version information
+ */
+ protected final static VersionInfo fromMap(String pckg, Map info,
+ ClassLoader clsldr) {
+ if (pckg == null) {
+ throw new IllegalArgumentException
+ ("Package identifier must not be null.");
+ }
+
+ String module = null;
+ String release = null;
+ String timestamp = null;
+
+ if (info != null) {
+ module = (String) info.get(PROPERTY_MODULE);
+ if ((module != null) && (module.length() < 1))
+ module = null;
+
+ release = (String) info.get(PROPERTY_RELEASE);
+ if ((release != null) && ((release.length() < 1) ||
+ (release.equals("${pom.version}"))))
+ release = null;
+
+ timestamp = (String) info.get(PROPERTY_TIMESTAMP);
+ if ((timestamp != null) &&
+ ((timestamp.length() < 1) ||
+ (timestamp.equals("${mvn.timestamp}")))
+ )
+ timestamp = null;
+ } // if info
+
+ String clsldrstr = null;
+ if (clsldr != null)
+ clsldrstr = clsldr.toString();
+
+ return new VersionInfo(pckg, module, release, timestamp, clsldrstr);
+ }
+
+} // class VersionInfo
diff --git a/src/org/apache/http/util/package.html b/src/org/apache/http/util/package.html
new file mode 100644
index 0000000..19d97b3
--- /dev/null
+++ b/src/org/apache/http/util/package.html
@@ -0,0 +1,45 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/package.html $
+ * $Revision: 496070 $
+ * $Date: 2007-01-14 04:18:34 -0800 (Sun, 14 Jan 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+Mostly utility classes with static helper methods for various purposes.
+
+The helper classes for resizable
+{@link org.apache.http.util.ByteArrayBuffer byte} and
+{@link org.apache.http.util.CharArrayBuffer char} arrays
+do not fall into this category.
+
+</body>
+</html>