Java tutorial
/** * Copyright 2006-2010 Soyatec * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * $Id$ */ package org.soyatec.windowsazure.internal.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.net.ssl.SSLHandshakeException; import org.apache.http.Header; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.NoHttpResponseException; import org.apache.http.auth.AuthScope; import org.apache.http.auth.NTCredentials; import org.apache.http.auth.params.AuthPNames; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpTrace; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.params.AuthPolicy; import org.apache.http.client.utils.URIUtils; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.params.ConnRoutePNames; 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.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; 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.HttpContext; import org.dom4j.Document; import org.dom4j.Element; import org.soyatec.windowsazure.authenticate.HttpRequestAccessor; import org.soyatec.windowsazure.authenticate.SharedAccessSignatureCredentials; import org.soyatec.windowsazure.authenticate.SharedKeyCredentials; import org.soyatec.windowsazure.blob.io.BlobMemoryStream; import org.soyatec.windowsazure.blob.io.BlobStream; import org.soyatec.windowsazure.constants.ConstChars; import org.soyatec.windowsazure.constants.XmlElementNames; import org.soyatec.windowsazure.error.StorageClientException; import org.soyatec.windowsazure.error.StorageErrorCode; import org.soyatec.windowsazure.error.StorageException; import org.soyatec.windowsazure.error.StorageExtendedErrorInformation; import org.soyatec.windowsazure.error.StorageServerException; import org.soyatec.windowsazure.error.WebException; import org.soyatec.windowsazure.internal.HttpMerge; import org.soyatec.windowsazure.internal.ResourceUriComponents; import org.soyatec.windowsazure.internal.StorageErrorCodeTranslator; import org.soyatec.windowsazure.internal.constants.HeaderNames; import org.soyatec.windowsazure.internal.constants.HttpMethod; import org.soyatec.windowsazure.internal.constants.HttpWebResponse; import org.soyatec.windowsazure.internal.constants.QueryParams; import org.soyatec.windowsazure.internal.constants.XmsVersion; import org.soyatec.windowsazure.internal.util.xml.XmlUtil; import org.soyatec.windowsazure.proxy.ProxyConfiguration; /** * Tools for create http request and send request. * */ public class HttpUtilities { static ProxyConfiguration proxy; // static final DefaultHttpRequestRetryHandler retryhandler = new // DefaultHttpRequestRetryHandler(); // retryhandler.setRequestSentRetryEnabled(false); // retryhandler.setRetryCount(3); static List<IHttpClientListener> listeners = new ArrayList<IHttpClientListener>(); private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() { static final int MAX_RETRY = 3; public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= MAX_RETRY) { // 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 SSLHandshakeException) { // Do not retry on SSL handshake exception return false; } HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST); boolean idempotent = (request instanceof HttpEntityEnclosingRequest); if (!idempotent) { // Retry if the request is considered idempotent return true; } return false; } }; /** * Add a HttpClient listener, which will be notified just after the * HttpClient instance is created and before any request is sent. * * @param listener */ public static void addHttpClientListener(IHttpClientListener listener) { if (!listeners.contains(listener)) listeners.add(listener); } public static void removeHttpClientListener(IHttpClientListener listener) { listeners.remove(listener); } public static void setProxy(ProxyConfiguration proxy) { HttpUtilities.proxy = proxy; } private static void addProxyConfig(DefaultHttpClient httpClient) { Properties prop = System.getProperties(); String proxyHost = prop.getProperty("http.proxyHost"); Integer proxyPort = null; if (prop.getProperty("http.proxyPort") != null) { proxyPort = Integer.parseInt(prop.getProperty("http.proxyPort")); } String proxyUserName = prop.getProperty("http.proxyUser"); String proxyPassword = prop.getProperty("http.proxyPassword"); String proxyDomain = prop.getProperty("http.proxyDomain"); if (proxy != null) { proxyHost = proxy.getProxyHost(); proxyPort = proxy.getProxyPort(); proxyUserName = proxy.getProxyUsername(); proxyPassword = proxy.getProxyPassword(); proxyDomain = proxy.getProxyDomainname(); } if (proxyHost != null && proxyPort > 0) { Logger.debug(String.format("Using the proxy, proxyHost %s and proxyPort %d", proxyHost, proxyPort)); HttpHost proxyServer = new HttpHost(proxyHost, proxyPort); httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyServer); if (proxyUserName != null && proxyUserName.trim().length() > 0 && proxyPassword != null && proxyPassword.length() > 0) { Logger.debug("Proxy Username:" + proxyUserName); Logger.debug("Proxy Domain:" + proxyDomain); AuthScope authScope = new AuthScope(proxyHost, proxyPort, null); NTCredentials credentials = new NTCredentials(proxyUserName, proxyPassword, "", proxyDomain); httpClient.getCredentialsProvider().setCredentials(authScope, credentials); // Set NTLM authentication List<String> authPrefs = new ArrayList<String>(); authPrefs.add(AuthPolicy.NTLM); httpClient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authPrefs); } } } // private static void addProxyConfig(DefaultHttpClient httpClient) { // if (!proxyExists()) // return; // // Properties prop = System.getProperties(); // String proxyHost = prop.getProperty("http.proxyHost"); // int proxyPort = Integer.parseInt(prop.getProperty("http.proxyPort")); // String username = prop.getProperty("http.proxyUser"); // String password = prop.getProperty("http.proxyPassword"); // // ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner( // httpClient.getConnectionManager().getSchemeRegistry(), // ProxySelector.getDefault()); // httpClient.setRoutePlanner(routePlanner); // // httpClient.getCredentialsProvider().setCredentials( // new AuthScope(proxyHost, proxyPort), // new UsernamePasswordCredentials(username, password)); // // HttpHost proxy = new HttpHost(proxyHost, proxyPort); // httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, // proxy); // // } // public static void setProxy(String host, int port) { // setProxy(host, port, null, null); // } // // public static void setProxy(String host, int port, String username, // String password) { // Properties prop = System.getProperties(); // // prop.setProperty("proxySet", "true"); // System.setProperty("http.proxyUser", username); // System.setProperty("http.proxyPassword", password); // prop.setProperty("http.proxyHost", host); // prop.setProperty("http.proxyPort", String.valueOf(port)); // prop.setProperty("https.proxyHost", host); // prop.setProperty("https.proxyPort", String.valueOf(port)); // // } public static boolean proxyExists() { Properties prop = System.getProperties(); if (prop.get("http.proxyHost") != null && prop.get("http.proxyPort") != null) return true; if (proxy != null) { String proxyHost = proxy.getProxyHost(); int proxyPort = proxy.getProxyPort(); if (proxyHost != null && proxyPort > 0) return true; } return false; } public static void removeProxyConfig() { Properties prop = System.getProperties(); prop.remove("proxySet"); prop.remove("http.proxyHost"); prop.remove("http.proxyPort"); prop.remove("http.nonProxyHosts"); prop.remove("https.proxyHost"); prop.remove("https.proxyPort"); prop.remove("https.nonProxyHosts"); prop.remove("http.proxyUser"); prop.remove("http.proxyPassword"); proxy = null; } /** * Create the http request with common headers. * * @param uri * @param method * @param timeout * @return HttpRequest */ public static HttpRequest createHttpRequestWithCommonHeaders(URI uri, String method, TimeSpan timeout) { HttpUriRequest request = createHttpRequest(uri, method); // Some header setting // request.Timeout = (int)timeout.TotalMilliseconds; if (timeout != null) { request.addHeader(HeaderNames.Sotimeout, Long.toString(timeout.toMilliseconds())); } // request.ReadWriteTimeout = (int)timeout.TotalMilliseconds; // request.ContentLength = 0; if (request.getHeaders(HeaderNames.ContentLength) == null || request.getHeaders(HeaderNames.ContentLength).length <= 0) { if (!request.getMethod().equals(HttpMethod.Put) && !request.getMethod().equals(HttpMethod.Post)) { // not set content length header for put method request.addHeader(HeaderNames.ContentLength, "0"); } } // set timeout request.addHeader(HeaderNames.StorageDateTime, Utilities.getUTCTime()); return request; } /** * Create the service httpReauest. * * @param uri * @param method * @return HttpRequest */ public static HttpUriRequest createServiceHttpRequest(URI uri, String method) { HttpUriRequest request = createHttpRequest(uri, method); request.addHeader(HeaderNames.ApiVersion, XmsVersion.VERSION_2009_10_01); return request; } /** * Add the metadata headers to the HttpRequest. * * @param request * @param metadata */ public static void addMetadataHeaders(HttpRequest request, NameValueCollection metadata) { for (Object keyObj : metadata.keySet()) { String key = (String) keyObj; String headerName = HeaderNames.PrefixForMetadata + key; request.addHeader(headerName.toLowerCase(), metadata.getMultipleValuesAsString(key)); } } /** * Create a httpRequest with the uri and method. * * @param uri * @param method * @return HttpUriRequest */ public static HttpUriRequest createHttpRequest(URI uri, String method) { HttpUriRequest request; if (method.equals(HttpMethod.Get)) { request = new HttpGet(uri); } else if (method.equals(HttpMethod.Post)) { request = new HttpPost(uri); } else if (method.equals(HttpMethod.Delete)) { request = new HttpDelete(uri); } else if (method.equals(HttpMethod.Head)) { request = new HttpHead(uri); } else if (method.equals(HttpMethod.Options)) { request = new HttpOptions(uri); } else if (method.equals(HttpMethod.Put)) { request = new HttpPut(uri); } else if (method.equals(HttpMethod.Trace)) { request = new HttpTrace(uri); } else if (method.equals(HttpMerge.METHOD_NAME)) { request = new HttpMerge(uri); } else { throw new IllegalArgumentException(MessageFormat.format("{0} is not a valid HTTP method.", method)); } return request; } /** * Get the HttpsClient of a SSLSocketFactory. * * @param factory * @return HttpsClient * @throws Exception */ public static HttpClient createHttpsClient(SSLSocketFactory factory) throws Exception { HttpParams params = new BasicHttpParams(); // params.setParameter(CoreProtocolPNames.USER_AGENT, // "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"); // params.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, // Boolean.FALSE); // params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, // "UTF-8"); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // HttpProtocolParams.setContentCharset(params, "UTF-8"); final SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", factory, 443)); final ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry); DefaultHttpClient client = new DefaultHttpClient(manager, params); addProxyConfig(client); // client.setHttpRequestRetryHandler(requestRetryHandler); notifyListener(client); return client; } private static HttpClient createHttpClient() { HttpParams params = new BasicHttpParams(); ConnManagerParams.setMaxTotalConnections(params, 100); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); // Create an HttpClient with the ThreadSafeClientConnManager. // This connection manager must be used if more than one thread will // be using the HttpClient. ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); DefaultHttpClient httpClient = new DefaultHttpClient(cm, params); addProxyConfig(httpClient); notifyListener(httpClient); return httpClient; } private static void notifyListener(DefaultHttpClient httpClient) { if (listeners.size() > 0) { for (IHttpClientListener listener : listeners) { listener.onCreate(httpClient); } } } /** * Get the HttpWebResponse with a HttpRequest and SSLSocketFactory. * * @param request * @param factory * @return the HttpWebResponse with a HttpRequest and SSLSocketFactory. * @throws Exception */ public static HttpWebResponse getSSLReponse(HttpUriRequest request, SSLSocketFactory factory) throws Exception { HttpClient client = HttpUtilities.createHttpsClient(factory); try { return new HttpWebResponse(client.execute(request)); } finally { // When HttpClient instance is no longer needed, // shut down the connection manager to ensure // immediate deallocation of all system resources // client.getConnectionManager().shutdown(); } } /** * Get the HttpWebResponse with a HttpRequest. * * @param request * @return HttpWebResponse * @throws Exception */ public static HttpWebResponse getResponse(HttpRequest request) throws Exception { HttpClient httpClient = createHttpClient(); HttpParams params = httpClient.getParams(); try { Long parseLong = Long.parseLong(request.getLastHeader(HeaderNames.Sotimeout).getValue()); request.removeHeader(request.getLastHeader(HeaderNames.Sotimeout)); // so timeout HttpConnectionParams.setConnectionTimeout(params, parseLong.intValue()); // connection timeout HttpConnectionParams.setSoTimeout(params, parseLong.intValue()); } catch (Exception e) { // Use default timeout setting... } try { if (request instanceof HttpUriRequest) { return new HttpWebResponse(httpClient.execute((HttpUriRequest) request)); } else { throw new IllegalArgumentException("Request is invalid"); } } finally { // When HttpClient instance is no longer needed, // shut down the connection manager to ensure // immediate deallocation of all system resources // httpClient.getConnectionManager().shutdown(); } } /** * Unexpected response code. Just throw a exception * * @param response * @throws StorageServerException * Warp all exception for bad response */ public static void processUnexpectedStatusCode(HttpWebResponse response) throws StorageServerException { StorageExtendedErrorInformation detail = null; if (response.getStream() != null) { detail = new StorageExtendedErrorInformation(); detail.setErrorBody(convertStreamToString(response.getStream())); } // Append the error response to exception detail message String exceptionMessage = response.getStatusDescription(); if (detail != null) { exceptionMessage = exceptionMessage + "\r\n" + detail.getErrorBody(); } response.close(); throw new StorageServerException(StorageErrorCode.ServiceBadResponse, exceptionMessage, response.getStatusCode(), detail, null); } /** * Convert the inputStream to a string. * * @param is * InputStream * @return string */ public static String convertStreamToString(InputStream is) { if (is == null) { return null; } /* * To convert the InputStream to String we use the * BufferedReader.readLine() method. We iterate until the BufferedReader * return null which means there's no more data to read. Each line will * appended to a StringBuilder and returned as String. */ BufferedReader reader = null; StringBuilder sb = new StringBuilder(); try { reader = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { // e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { // e.printStackTrace(); } } // FIX "xx?xml version="1.0" encoding="utf-8"?>" String xmlContent = sb.toString(); int pos = xmlContent.indexOf("?xml"); if (pos > -1) return "<" + xmlContent.substring(pos); else return xmlContent; } private static String[] split(String str, String sep) { int pos = str.indexOf(sep); return new String[] { str.substring(0, pos), str.substring(pos + 1) }; } /** * Parse query string to NameValueCollection object * * @param query * @return NameValueCollection */ public static NameValueCollection parseQueryString(String query) { NameValueCollection map = new NameValueCollection(); if (query == null) { return map; } String[] params = query.split(ConstChars.Ampersand); for (String param : params) { if (!param.contains(ConstChars.Equal)) { throw new IllegalArgumentException(MessageFormat.format("Query string \"{0}\" is invalid.", param)); } String[] nameValue = split(param, ConstChars.Equal);// param.split(ConstChars.Equal); // @FIX blockId // contains = map.put(nameValue[0], nameValue[1]); } return map; } /** * Parse the httpRequest to NameValueCollection object * * @param request * @return NameValueCollection */ public static NameValueCollection parseHttpHeaders(HttpRequest request) { NameValueCollection map = new NameValueCollection(); for (Header header : request.getAllHeaders()) { map.put(header.getName(), header.getValue()); } return map; } /** * Parse the httpRequest to string. * * @param request * @return string after parse */ public static String parseRequestContentType(HttpRequest request) { Header[] headers = request.getHeaders(HeaderNames.ContentType); if (headers != null) { for (Header header : headers) { if (header != null && !Utilities.isNullOrEmpty(header.getValue())) { return header.getValue(); } } } return Utilities.emptyString(); } /** * Translate Exception to StorageException. * * @param e * @return StorageException */ public static StorageException translateWebException(Exception e) { if (e instanceof StorageException) { return (StorageException) e; } if ((e instanceof WebException)) { WebException we = (WebException) e; HttpWebResponse response = we.getResponse(); if (response != null) { StorageExtendedErrorInformation extendedError = getExtendedErrorDetailsFromResponse( response.getStream(), response.getContentLength()); StorageException translatedException = null; if (extendedError != null) { translatedException = translateExtendedError(extendedError, response.getStatusCode(), response.getStatusDescription(), e); if (translatedException != null) { return translatedException; } } translatedException = translateFromHttpStatus(response.getStatusCode(), response.getStatusDescription(), extendedError, we); if (translatedException != null) { return translatedException; } } switch (we.getStatus()) { case RequestCanceled: return new StorageServerException(StorageErrorCode.ServiceTimeout, "The server request did not complete within the specified timeout", HttpStatus.SC_GATEWAY_TIMEOUT, we); case ConnectFailure: return new StorageServerException(StorageErrorCode.TransportError, "Connect to server failed", HttpStatus.SC_FAILED_DEPENDENCY, we); default: return new StorageServerException(StorageErrorCode.ServiceInternalError, "The server encountered an unknown failure: " + e.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR, we); } } return new StorageException(e); } private static StorageException translateFromHttpStatus(int statusCode, String statusDescription, StorageExtendedErrorInformation details, Exception inner) { switch (statusCode) { case HttpStatus.SC_FORBIDDEN: return new StorageClientException(StorageErrorCode.AccessDenied, statusDescription, HttpStatus.SC_FORBIDDEN, details, inner); case HttpStatus.SC_GONE: case HttpStatus.SC_NOT_FOUND: return new StorageClientException(StorageErrorCode.ResourceNotFound, statusDescription, statusCode, details, inner); case HttpStatus.SC_BAD_REQUEST: return new StorageClientException(StorageErrorCode.BadRequest, statusDescription, statusCode, details, inner); case HttpStatus.SC_PRECONDITION_FAILED: case HttpStatus.SC_NOT_MODIFIED: return new StorageClientException(StorageErrorCode.BadRequest, statusDescription, statusCode, details, inner); case HttpStatus.SC_CONFLICT: return new StorageClientException(StorageErrorCode.ResourceAlreadyExists, statusDescription, statusCode, details, inner); case HttpStatus.SC_GATEWAY_TIMEOUT: return new StorageServerException(StorageErrorCode.ServiceTimeout, statusDescription, statusCode, details, inner); case HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE: return new StorageClientException(StorageErrorCode.BadRequest, statusDescription, statusCode, details, inner); case HttpStatus.SC_INTERNAL_SERVER_ERROR: return new StorageServerException(StorageErrorCode.ServiceInternalError, statusDescription, statusCode, details, inner); case HttpStatus.SC_BAD_GATEWAY: return new StorageServerException(StorageErrorCode.BadGateway, statusDescription, statusCode, details, inner); } return null; } private static StorageException translateExtendedError(StorageExtendedErrorInformation details, int statusCode, String statusDescription, Exception e) { StorageErrorCode errorCode = StorageErrorCodeTranslator .translateStorageErrorCodeString(details.getErrorCode()); if (errorCode != StorageErrorCode.None) { return new StorageClientException(errorCode, statusDescription, statusCode, details, e); } errorCode = StorageErrorCodeTranslator.translateStorageErrorCodeString(details.getErrorCode()); if (errorCode != StorageErrorCode.None) { return new StorageServerException(errorCode, statusDescription, statusCode, details, e); } return null; } // This is the limit where we allow for the error message returned by the // server. // Message longer than that will be truncated. private final static int ErrorTextSizeLimit = 8 * 1024; private static StorageExtendedErrorInformation getExtendedErrorDetailsFromResponse(InputStream stream, long contentLength) { int bytesToRead = (int) Math.max(contentLength, ErrorTextSizeLimit); byte[] responseBuffer = new byte[bytesToRead]; int bytesRead = copyStreamToBuffer(stream, responseBuffer, bytesToRead); return getErrorDetailsFromStream(new BlobMemoryStream(responseBuffer, 0, bytesRead)); } private static StorageExtendedErrorInformation getErrorDetailsFromStream(BlobStream stream) { StorageExtendedErrorInformation extendedError = new StorageExtendedErrorInformation(); try { Document doc = XmlUtil.parseXmlString(new String(stream.getBytes())); Element root = doc.getRootElement(); extendedError.setErrorCode(root.elementText(XmlElementNames.ErrorCode)); extendedError.setErrorMessage(root.elementText(XmlElementNames.ErrorMessage)); NameValueCollection details = new NameValueCollection(); extendedError.setAdditionalDetails(details); for (Object o : root.elements()) { Element e = (Element) o; if (e.getName().equals(XmlElementNames.ErrorException)) { details.put(XmlElementNames.ErrorExceptionMessage, e.elementText(XmlElementNames.ErrorExceptionMessage)); details.put(XmlElementNames.ErrorExceptionStackTrace, e.elementText(XmlElementNames.ErrorExceptionStackTrace)); } else { details.put(e.getName(), e.getText()); } } } catch (Exception e) { return null; } return extendedError; } private static int copyStreamToBuffer(InputStream stream, byte[] buffer, int bytesToRead) { int n = 0; int amountLeft = bytesToRead; do { try { n = stream.read(buffer, bytesToRead - amountLeft, amountLeft); } catch (IOException e) { Logger.error("", e); break; } amountLeft -= n; } while (n > 0); return bytesToRead - amountLeft; } /** * Create a request URI. * * @param baseUri * @param usePathStyleUris * @param accountName * @param containerName * @param blobName * @param timeout * @param queryParameters * @param uriComponents * @return a URI */ public static URI createRequestUri(URI baseUri, boolean usePathStyleUris, String accountName, String containerName, String blobName, TimeSpan timeout, NameValueCollection queryParameters, ResourceUriComponents uriComponents) { return createRequestUri(baseUri, usePathStyleUris, accountName, containerName, blobName, timeout, queryParameters, uriComponents, (String) null); } public static URI createRequestUri(URI baseUri, boolean usePathStyleUris, String accountName, String containerName, String blobName, TimeSpan timeout, NameValueCollection queryParameters, ResourceUriComponents uriComponents, SharedKeyCredentials credentials) { String appendQuery = ""; if (credentials instanceof SharedAccessSignatureCredentials) { SharedAccessSignatureCredentials sasCredentials = (SharedAccessSignatureCredentials) credentials; appendQuery = sasCredentials.getSas(); } return createRequestUri(baseUri, usePathStyleUris, accountName, containerName, blobName, timeout, queryParameters, uriComponents, appendQuery); } /** * Create a request URI. * * @param baseUri * @param usePathStyleUris * @param accountName * @param containerName * @param blobName * @param timeout * @param queryParameters * @param uriComponents * @param appendQuery * @return URI */ public static URI createRequestUri(URI baseUri, boolean usePathStyleUris, String accountName, String containerName, String blobName, TimeSpan timeout, NameValueCollection queryParameters, ResourceUriComponents uriComponents, String appendQuery) { URI uri = HttpRequestAccessor.constructResourceUri(baseUri, uriComponents, usePathStyleUris); if (queryParameters != null) { if (queryParameters.get(QueryParams.QueryParamTimeout) == null && timeout != null) { queryParameters.put(QueryParams.QueryParamTimeout, timeout.toSeconds()); } StringBuilder sb = new StringBuilder(); boolean firstParam = true; boolean appendBlockAtTail = false; for (Object key : queryParameters.keySet()) { String queryKey = (String) key; if (queryKey.equalsIgnoreCase(QueryParams.QueryParamBlockId)) { appendBlockAtTail = true; continue; } if (!firstParam) { sb.append("&"); } sb.append(Utilities.encode(queryKey)); sb.append('='); sb.append(Utilities.encode(queryParameters.getSingleValue(queryKey))); firstParam = false; } /* * You shuold add blockid as the last query parameters for put block * request, or an exception you will get. */ if (appendBlockAtTail) { String queryKey = QueryParams.QueryParamBlockId; sb.append("&"); sb.append(Utilities.encode(queryKey)); sb.append('='); sb.append(Utilities.encode(queryParameters.getSingleValue(queryKey))); } if (!Utilities.isNullOrEmpty(appendQuery)) { if (sb.length() > 0) { sb.append("&"); } // @NOTE: escape char sb.append(appendQuery.replaceAll(" ", "%20")); } if (sb.length() > 0) { try { String p = getNormalizePath(uri).replaceAll(" ", "%20"); return URIUtils.createURI(uri.getScheme(), uri.getHost(), uri.getPort(), p, (uri.getQuery() == null ? Utilities.emptyString() : uri.getQuery()) + sb.toString(), uri.getFragment()); } catch (URISyntaxException e) { Logger.error("", e); } } return uri; } else { return uri; } } /** * Get normalize path * * @param uri * @return String */ public static String getNormalizePath(URI uri) { if (Utilities.isNullOrEmpty(uri.getPath())) { return ConstChars.Slash; } else { if (!uri.getPath().startsWith(ConstChars.Slash)) { return ConstChars.Slash + uri.getPath(); } else { return uri.getPath(); } } } /** * Remove the query part from URI. * * @param uri * @return URI after remove the query part. */ public static URI removeQueryPart(URI uri) { try { return URIUtils.createURI(uri.getScheme(), uri.getHost(), uri.getPort(), uri.getPath(), null, null); } catch (URISyntaxException e) { Logger.error("Remove query part from uri failed.", e); return uri; } } }