/* * (non-Javadoc) * * @see * com.sun.jersey.api.client.filter.ClientFilter#handle(com.sun.jersey.api * .client.ClientRequest) */ @Override public ClientResponse handle(ClientRequest cr) { String key = getKey(); if (cr.getProperties().containsKey(key)) { return this.getNext().handle(cr); } cr.getProperties().put(key, this); return doHandle(cr); }
private Request buildRequest(ClientRequest req) throws IOException { final Request request = client.newRequest(req.getURI()).method(HttpMethod.fromString(req.getMethod())); if (req.getEntity() != null) { final RequestEntityWriter writer = getRequestEntityWriter(req); final PipedOutputStream output = new PipedOutputStream(); final PipedInputStream input = new PipedInputStream(output); request.content(new InputStreamContentProvider(input)); writer.writeRequestEntity(output); } return request; }
@Override public ClientResponse handle(ClientRequest cr) throws ClientHandlerException { // Only sign if no other filter is handling authorization if (cr.getProperties().get(SharedKeyUtils.AUTHORIZATION_FILTER_MARKER) == null) { cr.getProperties().put(SharedKeyUtils.AUTHORIZATION_FILTER_MARKER, null); // Register ourselves as listener so we are called back when the entity is // written to the output stream by the next filter in line. if (cr.getProperties().get(EntityStreamingListener.class.getName()) == null) { cr.getProperties().put(EntityStreamingListener.class.getName(), this); } } return this.getNext().handle(cr); }
private void addOptionalDateHeader(ClientRequest cr) { String date = getHeader(cr, "Date"); if (date == "") { date = new RFC1123DateConverter().format(new Date()); cr.getHeaders().add("Date", date); } }
public ClientResponse handle(ClientRequest cr) { cr.getHeaders() .add( HttpHeaders.AUTHORIZATION, "Basic " + new String(Base64.encode(user + ":" + pass), Charset.forName("ASCII"))); ClientResponse resp = getNext().handle(cr); return resp; }
/* * (non-Javadoc) * * @see * com.microsoft.windowsazure.services.core.IdempotentClientFilter#doHandle * (com.sun.jersey.api.client.ClientRequest) */ @Override public ClientResponse doHandle(ClientRequest cr) { MultivaluedMap<String, Object> headers = cr.getHeaders(); headers.add("DataServiceVersion", "3.0"); headers.add("MaxDataServiceVersion", "3.0"); headers.add("x-ms-version", "2.5"); return getNext().handle(cr); }
private void writeOutBoundHeaders(MultivaluedMap<String, Object> headers, Request request) { for (Map.Entry<String, List<Object>> e : headers.entrySet()) { final List<Object> vs = e.getValue(); if (vs.size() == 1) { request.header(e.getKey(), ClientRequest.getHeaderValue(vs.get(0))); } else { final StringBuilder header = new StringBuilder(); for (Object v : e.getValue()) { if (header.length() > 0) { header.append(','); } header.append(ClientRequest.getHeaderValue(v)); } request.header(e.getKey(), header.toString()); } } }
private void writeOutBoundHeaders(MultivaluedMap<String, Object> metadata, HttpURLConnection uc) { for (Map.Entry<String, List<Object>> e : metadata.entrySet()) { List<Object> vs = e.getValue(); if (vs.size() == 1) { uc.setRequestProperty(e.getKey(), ClientRequest.getHeaderValue(vs.get(0))); } else { StringBuilder b = new StringBuilder(); boolean add = false; for (Object v : e.getValue()) { if (add) b.append(','); add = true; b.append(ClientRequest.getHeaderValue(v)); } uc.setRequestProperty(e.getKey(), b.toString()); } } }
/** * This format supports Shared Key authentication for the 2009-09-19 version of the Blob and Queue * services. Construct the CanonicalizedResource string in this format as follows: * * <p>1. Beginning with an empty string (""), append a forward slash (/), followed by the name of * the account that owns the resource being accessed. * * <p>2. Append the resource's encoded URI path, without any query parameters. * * <p>3. Retrieve all query parameters on the resource URI, including the comp parameter if it * exists. * * <p>4. Convert all parameter names to lowercase. * * <p>5. Sort the query parameters lexicographically by parameter name, in ascending order. * * <p>6. URL-decode each query parameter name and value. * * <p>7. Append each query parameter name and value to the string in the following format, making * sure to include the colon (:) between the name and the value: * * <p>parameter-name:parameter-value * * <p>8. If a query parameter has more than one value, sort all values lexicographically, then * include them in a comma-separated list: * * <p>parameter-name:parameter-value-1,parameter-value-2,parameter-value-n * * <p>9. Append a new line character (\n) after each name-value pair. */ private String getCanonicalizedResource(ClientRequest cr) { // 1. Beginning with an empty string (""), append a forward slash (/), followed by the name of // the account that owns // the resource being accessed. String result = "/" + this.accountName; // 2. Append the resource's encoded URI path, without any query parameters. result += cr.getURI().getPath(); // 3. Retrieve all query parameters on the resource URI, including the comp parameter if it // exists. // 6. URL-decode each query parameter name and value. List<QueryParam> queryParams = SharedKeyUtils.getQueryParams(cr.getURI().getQuery()); // 4. Convert all parameter names to lowercase. for (QueryParam param : queryParams) { param.setName(param.getName().toLowerCase(Locale.US)); } // 5. Sort the query parameters lexicographically by parameter name, in ascending order. Collections.sort(queryParams); // 7. Append each query parameter name and value to the string // 8. If a query parameter has more than one value, sort all values lexicographically, then // include them in a comma-separated list for (int i = 0; i < queryParams.size(); i++) { QueryParam param = queryParams.get(i); List<String> values = param.getValues(); // Collections.sort(values); // 9. Append a new line character (\n) after each name-value pair. result += "\n"; result += param.getName(); result += ":"; for (int j = 0; j < values.size(); j++) { if (j > 0) { result += ","; } result += values.get(j); } } return result; }
public ClientResponse handle(ClientRequest clientRequest) { byte[] requestEntity = writeRequestEntity(clientRequest); InBoundHeaders rh = getInBoundHeaders(clientRequest.getMetadata()); final ContainerRequest cRequest = new ContainerRequest( w, clientRequest.getMethod(), baseUri, clientRequest.getURI(), rh, new ByteArrayInputStream(requestEntity)); // TODO this is a hack List<String> cookies = cRequest.getRequestHeaders().get("Cookie"); if (cookies != null) { for (String cookie : cookies) { if (cookie != null) cRequest.getCookies().putAll(HttpHeaderReader.readCookies(cookie)); } } final TstContainerResponseWriter writer = new TstContainerResponseWriter(); final ContainerResponse cResponse = new ContainerResponse(w, cRequest, writer); try { w.handleRequest(cRequest, cResponse); } catch (IOException e) { throw new ContainerException(e); } byte[] responseEntity = writer.baos.toByteArray(); ClientResponse clientResponse = new ClientResponse( cResponse.getStatus(), getInBoundHeaders(cResponse.getHttpHeaders()), new ByteArrayInputStream(responseEntity), getMessageBodyWorkers()); clientResponse.getProperties().put("request.entity", requestEntity); clientResponse.getProperties().put("response.entity", responseEntity); return clientResponse; }
/* * StringToSign = VERB + "\n" + * Content-Encoding + "\n" * Content-Language + "\n" * Content-Length + "\n" * Content-MD5 + "\n" + * Content-Type + "\n" + * Date + "\n" + * If-Modified-Since + "\n" * If-Match + "\n" * If-None-Match + "\n" * If-Unmodified-Since + "\n" * Range + "\n" * CanonicalizedHeaders + * CanonicalizedResource; */ public void sign(ClientRequest cr) { // gather signed material addOptionalDateHeader(cr); // build signed string String stringToSign = cr.getMethod() + "\n" + getHeader(cr, "Content-Encoding") + "\n" + getHeader(cr, "Content-Language") + "\n" + getHeader(cr, "Content-Length") + "\n" + getHeader(cr, "Content-MD5") + "\n" + getHeader(cr, "Content-Type") + "\n" + getHeader(cr, "Date") + "\n" + getHeader(cr, "If-Modified-Since") + "\n" + getHeader(cr, "If-Match") + "\n" + getHeader(cr, "If-None-Match") + "\n" + getHeader(cr, "If-Unmodified-Since") + "\n" + getHeader(cr, "Range") + "\n"; stringToSign += getCanonicalizedHeaders(cr); stringToSign += getCanonicalizedResource(cr); if (log.isDebugEnabled()) { log.debug(String.format("String to sign: \"%s\"", stringToSign)); } // System.out.println(String.format("String to sign: \"%s\"", stringToSign)); String signature = this.signer.sign(stringToSign); cr.getHeaders().putSingle("Authorization", "SharedKey " + this.accountName + ":" + signature); }
@Override public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException { final MultivaluedMap<String, Object> headers = clientRequest.getHeaders(); List<Object> hcookies = headers.get(COOKIE_HEADER); if (hcookies == null) { hcookies = new ArrayList<Object>(); } hcookies.addAll(cookies); headers.put(COOKIE_HEADER, hcookies); return getNext().handle(clientRequest); }
public void configureRequest( final RequestBuilder requestBuilder, final ClientRequest cr, final boolean needsBody) { final Map<String, Object> props = cr.getProperties(); // Set the read timeout final Integer readTimeout = (Integer) props.get(AhcConfig.PROPERTY_READ_TIMEOUT); if (readTimeout != null) { final PerRequestConfig c = new PerRequestConfig(); c.setRequestTimeoutInMs(readTimeout); requestBuilder.setPerRequestConfig(c); } if (cr.getEntity() != null && needsBody) { final RequestEntityWriter re = getRequestEntityWriter(cr); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { re.writeRequestEntity( new CommittingOutputStream(baos) { @Override protected void commit() throws IOException { configureHeaders(cr.getHeaders(), requestBuilder); } }); } catch (final IOException ex) { throw new ClientHandlerException(ex); } final byte[] content = baos.toByteArray(); requestBuilder.setBody( new Request.EntityWriter() { @Override public void writeEntity(final OutputStream out) throws IOException { out.write(content); } }); } else { configureHeaders(cr.getHeaders(), requestBuilder); } }
@Override public ClientResponse handle(ClientRequest cr) throws ClientHandlerException { try { final Request request = buildRequest(cr); writeOutBoundHeaders(cr.getHeaders(), request); final ContentResponse response = request.send(); return new ClientResponse( response.getStatus(), getInBoundHeaders(response), new ByteArrayInputStream(response.getContent()), getMessageBodyWorkers()); } catch (InterruptedException | TimeoutException | ExecutionException | IOException e) { throw new ClientHandlerException(e); } }
@Override public void executeMethod(final HttpMethod method, final ClientRequest cr) { final Map<String, Object> props = cr.getProperties(); method.setDoAuthentication(true); final HttpMethodParams methodParams = method.getParams(); // Set the handle cookies property if (!cr.getPropertyAsFeature(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES)) { methodParams.setCookiePolicy(CookiePolicy.IGNORE_COOKIES); } // Set the interactive and credential provider properties if (cr.getPropertyAsFeature(ApacheHttpClientConfig.PROPERTY_INTERACTIVE)) { CredentialsProvider provider = (CredentialsProvider) props.get(ApacheHttpClientConfig.PROPERTY_CREDENTIALS_PROVIDER); if (provider == null) { provider = DEFAULT_CREDENTIALS_PROVIDER; } methodParams.setParameter(CredentialsProvider.PROVIDER, provider); } else { methodParams.setParameter(CredentialsProvider.PROVIDER, null); } // Set the read timeout final Integer readTimeout = (Integer) props.get(ApacheHttpClientConfig.PROPERTY_READ_TIMEOUT); if (readTimeout != null) { methodParams.setSoTimeout(readTimeout); } if (method instanceof EntityEnclosingMethod) { final EntityEnclosingMethod entMethod = (EntityEnclosingMethod) method; if (cr.getEntity() != null) { final RequestEntityWriter re = getRequestEntityWriter(cr); final Integer chunkedEncodingSize = (Integer) props.get(ApacheHttpClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE); if (chunkedEncodingSize != null) { // There doesn't seems to be a way to set the chunk size. entMethod.setContentChunked(true); // It is not possible for a MessageBodyWriter to modify // the set of headers before writing out any bytes to // the OutputStream // This makes it impossible to use the multipart // writer that modifies the content type to add a boundary // parameter writeOutBoundHeaders(cr.getHeaders(), method); // Do not buffer the request entity when chunked encoding is // set entMethod.setRequestEntity( new RequestEntity() { @Override public boolean isRepeatable() { return false; } @Override public void writeRequest(OutputStream out) throws IOException { re.writeRequestEntity(out); } @Override public long getContentLength() { return re.getSize(); } @Override public String getContentType() { return re.getMediaType().toString(); } }); } else { entMethod.setContentChunked(false); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { re.writeRequestEntity( new CommittingOutputStream(baos) { @Override protected void commit() throws IOException { writeOutBoundHeaders(cr.getMetadata(), method); } }); } catch (IOException ex) { throw new ClientHandlerException(ex); } final byte[] content = baos.toByteArray(); entMethod.setRequestEntity( new RequestEntity() { @Override public boolean isRepeatable() { return true; } @Override public void writeRequest(OutputStream out) throws IOException { out.write(content); } @Override public long getContentLength() { return content.length; } @Override public String getContentType() { return re.getMediaType().toString(); } }); } } } else { writeOutBoundHeaders(cr.getHeaders(), method); // Follow redirects method.setFollowRedirects( cr.getPropertyAsFeature(ApacheHttpClientConfig.PROPERTY_FOLLOW_REDIRECTS)); } try { httpClient.executeMethod( getHostConfiguration(httpClient, props), method, getHttpState(props)); } catch (Exception e) { method.releaseConnection(); throw new ClientHandlerException(e); } }
@Override public ClientResponse handle(final ClientRequest request) throws ClientHandlerException { // Remember if we sent a request a with headers boolean reqHadAuthHeaders = false; // Have we already login ? : Then add authorization info to the headers if (state.get().nextNonce != null) { // Remember we sent headers reqHadAuthHeaders = true; // Alias to string representation of qop String qopStr = null; if (state.get().qop != null) qopStr = (state.get().qop == QOP.AUTH_INT) ? "auth-int" : "auth"; // Init the value of the "authorized" header StringBuffer buff = new StringBuffer(); // Authorization scheme buff.append("Digest "); // Key/val pairs addKeyVal(buff, "username", this.user); addKeyVal(buff, "realm", state.get().realm); addKeyVal(buff, "nonce", state.get().nextNonce); if (state.get().opaque != null) addKeyVal(buff, "opaque", state.get().opaque); if (state.get().algorithm != null) addKeyVal(buff, "algorithm", state.get().algorithm, false); if (state.get().qop != null) addKeyVal(buff, "qop", qopStr, false); // if (this.domain != null) addKeyVal(buff, "domain", this.domain); // ------------------------------------------------------- // Compute the Digest Hash // ------------------------------------------------------- // HA1 String HA1 = concatMD5(this.user, state.get().realm, this.pass); // Get exact requested URI String uri = request.getURI().getPath(); // Repeat URI in header addKeyVal(buff, "uri", uri); // HA2 : Switch on qop String HA2; if (state.get().qop == QOP.AUTH_INT && (request.getEntity() != null)) { HA2 = concatMD5(request.getMethod(), uri, request.getEntity().toString()); } else { HA2 = concatMD5(request.getMethod(), uri); } // Compute response String response; if (state.get().qop == null) { // Simple response response = concatMD5(HA1, state.get().nextNonce, HA2); } else { // Quality of protection is set // Generate client nonce (UID) String cnonce = randHexBytes(CNONCE_NB_BYTES); // Counter in hexadecimal String nc = String.format("%08x", state.get().counter); state.get().counter += 1; // Add them to key/value pairs addKeyVal(buff, "cnonce", cnonce); addKeyVal(buff, "nc", nc, false); response = concatMD5(HA1, state.get().nextNonce, nc, cnonce, qopStr, HA2); } // Append the response addKeyVal(buff, "response", response); // Remove the last coma buff.deleteCharAt(buff.length() - 1); String authLine = buff.toString(); // Add the whole Authorization line to the header request.getMetadata().add(HttpHeaders.AUTHORIZATION, authLine); } // End of "we already logged in ?" // Forward the request to the next filter and get the result back ClientResponse response = getNext().handle(request); // The server asked for authentication ? (status 401) if (response.getResponseStatus() == Status.UNAUTHORIZED) { // Parse the www-authentication headers HashMap<String, String> map = parseHeaders(response.getHeaders().get(HttpHeaders.WWW_AUTHENTICATE)); // No digest authentication request found ? => We can do nothing more if (map == null) return response; // Get header values state.get().realm = map.get("realm"); state.get().nextNonce = map.get("nonce"); state.get().opaque = map.get("opaque"); state.get().algorithm = map.get("algorithm"); state.get().domain = map.get("domain"); // Parse Qop String qop = map.get("qop"); if (qop == null) { state.get().qop = null; } else { if (qop.contains("auth-int")) { state.get().qop = QOP.AUTH_INT; } else if (qop.contains("auth")) { state.get().qop = QOP.AUTH; } else { state.get().qop = null; } } // Parse "stale" String staleStr = map.get("stale"); boolean stale = (staleStr != null) && staleStr.toLowerCase().equals("true"); // Did we send the initial request without headers ? // Or the server asked to retry with new nonce ? if (stale || !reqHadAuthHeaders) { // Then try to resent same request with updated headers return this.handle(request); } else { // We already tried to log, but the authentication failed : // Just forward this response return response; } } // Not 401 status : no authentication issue return response; } // End of #handle()
private ClientResponse _invoke(final ClientRequest ro) throws IOException { final HttpURLConnection uc; if (this.httpURLConnectionFactory == null) { uc = (HttpURLConnection) ro.getURI().toURL().openConnection(); } else { uc = this.httpURLConnectionFactory.getHttpURLConnection(ro.getURI().toURL()); } Integer readTimeout = (Integer) ro.getProperties().get(ClientConfig.PROPERTY_READ_TIMEOUT); if (readTimeout != null) { uc.setReadTimeout(readTimeout); } Integer connectTimeout = (Integer) ro.getProperties().get(ClientConfig.PROPERTY_CONNECT_TIMEOUT); if (connectTimeout != null) { uc.setConnectTimeout(connectTimeout); } Boolean followRedirects = (Boolean) ro.getProperties().get(ClientConfig.PROPERTY_FOLLOW_REDIRECTS); if (followRedirects != null) { uc.setInstanceFollowRedirects(followRedirects); } if (uc instanceof HttpsURLConnection) { HTTPSProperties httpsProperties = (HTTPSProperties) ro.getProperties().get(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES); if (httpsProperties != null) { httpsProperties.setConnection((HttpsURLConnection) uc); } } Boolean httpUrlConnectionSetMethodWorkaround = (Boolean) ro.getProperties().get(PROPERTY_HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND); if (httpUrlConnectionSetMethodWorkaround != null && httpUrlConnectionSetMethodWorkaround == true) { setRequestMethodUsingWorkaroundForJREBug(uc, ro.getMethod()); } else { uc.setRequestMethod(ro.getMethod()); } // Write the request headers writeOutBoundHeaders(ro.getHeaders(), uc); // Write the entity (if any) Object entity = ro.getEntity(); if (entity != null) { uc.setDoOutput(true); if (ro.getMethod().equalsIgnoreCase("GET")) { final Logger logger = Logger.getLogger(URLConnectionClientHandler.class.getName()); if (logger.isLoggable(Level.INFO)) { logger.log( Level.INFO, "GET method with entity will be most likely replaced by POST, see http://java.net/jira/browse/JERSEY-1161"); } } writeRequestEntity( ro, new RequestEntityWriterListener() { public void onRequestEntitySize(long size) { if (size != -1 && size < Integer.MAX_VALUE) { // HttpURLConnection uses the int type for content length uc.setFixedLengthStreamingMode((int) size); } else { // TODO it appears HttpURLConnection has some bugs in // chunked encoding // uc.setChunkedStreamingMode(0); Integer chunkedEncodingSize = (Integer) ro.getProperties().get(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE); if (chunkedEncodingSize != null) { uc.setChunkedStreamingMode(chunkedEncodingSize); } } } public OutputStream onGetOutputStream() throws IOException { return new CommittingOutputStream() { @Override protected OutputStream getOutputStream() throws IOException { return uc.getOutputStream(); } @Override public void commit() throws IOException { writeOutBoundHeaders(ro.getHeaders(), uc); } }; } }); } else { writeOutBoundHeaders(ro.getHeaders(), uc); } // Return the in-bound response return new URLConnectionResponse( uc.getResponseCode(), getInBoundHeaders(uc), getInputStream(uc), ro.getMethod(), uc); }
@Override public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException { int retryCount = 0; InputStream entityStream = null; if (clientRequest.getEntity() instanceof InputStream) entityStream = (InputStream) clientRequest.getEntity(); while (true) { try { // if using an InputStream, mark the stream so we can rewind it in case of an error if (entityStream != null && entityStream.markSupported()) entityStream.mark(config.getRetryBufferSize()); return getNext().handle(clientRequest); } catch (RuntimeException orig) { Throwable t = orig; // in this case, the exception was wrapped by Jersey if (t instanceof ClientHandlerException) t = t.getCause(); if (t instanceof AtmosException) { AtmosException ae = (AtmosException) t; // retry all 50x errors if (ae.getHttpCode() < 500) throw orig; // add small delay to Atmos code 1040 (server busy) if (ae.getErrorCode() == 1040) { try { Thread.sleep(ATMOS_1040_DELAY_MS); } catch (InterruptedException e) { log.warn("Interrupted while waiting after a 1040 response: " + e.getMessage()); } } // retry all IO exceptions unless wschecksum is enabled (can't overwrite data in this // case) } else if (!(t instanceof IOException) || clientRequest.getHeaders().getFirst(RestUtil.XHEADER_WSCHECKSUM) != null) throw orig; // only retry maxRetries times if (++retryCount > config.getMaxRetries()) throw orig; // attempt to reset InputStream if it has been read from if (entityStream != null) { if (!(entityStream instanceof MeasuredInputStream) || ((MeasuredInputStream) entityStream).getRead() > 0) { try { if (!entityStream.markSupported()) throw new IOException("Mark is not supported"); entityStream.reset(); } catch (IOException e) { log.warn("Could not reset entity stream for retry: " + e.getMessage()); throw orig; } } } log.info("Error received in response (" + t + "), retrying..."); // wait for retry delay if (config.getRetryDelayMillis() > 0) { try { Thread.sleep(config.getRetryDelayMillis()); } catch (InterruptedException e) { log.warn("Interrupted while waiting to retry: " + e.getMessage()); } } } } }
@Override public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException { clientRequest.getHeaders().add("Connection", "close"); return getNext().handle(clientRequest); }