Java tutorial
/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package storage.netty; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelProgressiveFuture; import io.netty.channel.ChannelProgressiveFutureListener; import io.netty.channel.DefaultFileRegion; import io.netty.channel.EventLoopGroup; import io.netty.channel.FileRegion; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpChunkedInput; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.QueryStringEncoder; import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import io.netty.handler.codec.http.multipart.DiskAttribute; import io.netty.handler.codec.http.multipart.DiskFileUpload; import io.netty.handler.codec.http.multipart.HttpDataFactory; import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; //import io.netty.util.internal.SocketUtils; import io.netty.handler.stream.ChunkedFile; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map.Entry; import java.util.TimeZone; import java.lang.String; import javax.activation.MimetypesFileTypeMap; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; /** * This class is meant to be run against {@link HttpUploadServer}. */ public final class HttpUploadClient { private String base_url, account_name, account_key, FILE; private Mac hmacSha256; private byte[] key; static final String AB = "abcdefghijklmnopqrstuvwxyz"; static SecureRandom rnd = new SecureRandom(); public HttpUploadClient(String account_name, String account_key) { this.base_url = "http://" + account_name + ".blob.core.windows.net"; this.account_name = account_name; this.account_key = account_key; } public void putBlob(String filepath) throws Exception { //putblob: http://sercan.blob.core.windows.net/containername/blobname this.FILE = filepath; String resourceUrl = "/mycontainer/" + randomString(5); String putBlobUrl = base_url + resourceUrl; URI uriSimple = new URI(putBlobUrl); String scheme = uriSimple.getScheme() == null ? "http" : uriSimple.getScheme(); String host = uriSimple.getHost() == null ? "127.0.0.1" : uriSimple.getHost(); int port = uriSimple.getPort(); if (port == -1) { if ("http".equalsIgnoreCase(scheme)) { port = 80; } else if ("https".equalsIgnoreCase(scheme)) { port = 443; } } if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { System.err.println("Only HTTP(S) is supported."); return; } final boolean ssl = "https".equalsIgnoreCase(scheme); final SslContext sslCtx; if (ssl) { sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } File file = new File(FILE); if (!file.canRead()) { throw new FileNotFoundException(FILE); } // Configure the client. EventLoopGroup group = new NioEventLoopGroup(); // setup the factory: here using a mixed memory/disk based on size threshold HttpDataFactory factory = new DefaultHttpDataFactory(true); // Disk if MINSIZE exceed DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) DiskFileUpload.baseDirectory = null; // system temp directory DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) DiskAttribute.baseDirectory = null; // system temp directory try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new HttpUploadClientInitializer(sslCtx)); // Simple Post form: factory used for big attributes formpost(b, host, port, uriSimple, resourceUrl, file, factory); } finally { // Shut down executor threads to exit. group.shutdownGracefully(); // Really clean all temporary files if they still exist factory.cleanAllHttpDatas(); } } /** * Standard post without multipart but already support on Factory (memory management) * * @return the list of HttpData object (attribute and file) to be reused on next post */ private void formpost(Bootstrap bootstrap, String host, int port, URI uriSimple, String resourceUrl, File file, HttpDataFactory factory) throws Exception { // Start the connection attempt. Channel channel = bootstrap.connect(host, port).sync().channel(); // Wait until the connection attempt succeeds or fails. //Channel channel = future.sync().channel(); // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.PUT, uriSimple.toASCIIString()); request.headers().set(HttpHeaderNames.HOST, host); request.headers().add("x-ms-version", "2016-05-31"); final DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); formatter.setTimeZone(TimeZone.getTimeZone("GMT")); String dateTime = formatter.format(new Date()); request.headers().set("x-ms-date", dateTime); request.headers().set("x-ms-blob-type", "BlockBlob"); request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); RandomAccessFile raf = new RandomAccessFile(file, "r"); long fileLength = raf.length(); HttpUtil.setContentLength(request, fileLength); setContentTypeHeader(request, file); // Use the PostBody encoder //HttpPostRequestEncoder bodyRequestEncoder = // new HttpPostRequestEncoder(factory, request, false); // false => not multipart // add Form attribute //bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false); request.headers().set("Authorization", "SharedKey " + account_name + ":" + AuthorizationHeader(account_name, account_key, "PUT", dateTime, request, resourceUrl, "", "")); channel.write(request); // ByteBuf buffer = Unpooled.copiedBuffer(Files.readAllBytes(file.toPath())); //ByteBuf buffer = Unpooled.buffer(new FileInputStream(file), (int) file.length()); ChannelFuture sendFileFuture = channel.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), channel.newProgressivePromise()); // Write the end marker. ChannelFuture lastContentFuture = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); sendFileFuture.addListener(new ChannelProgressiveFutureListener() { @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { System.err.println(future.channel() + " Transfer complete."); } }); } public String AuthorizationHeader(String storageAccountName, String storageAccountKey, String method, String now, HttpRequest request, String resourceUrl, String ifMatch, String md5) throws InvalidKeyException { String MessageSignature; // This is the raw representation of the message signature. MessageSignature = String.format("%s\n\n\n%s\n%s\n%s\n\n\n%s\n\n\n\n%s%s", method, request.headers().getAsString("Content-Length"), md5, request.headers().getAsString("Content-Type"), ifMatch, GetCanonicalizedHeaders(request), GetCanonicalizedResource(resourceUrl, storageAccountName)); System.out.println(MessageSignature); // Create the HMACSHA256 version of the storage key. String AuthorizationHeader = computeHmac256(storageAccountKey, MessageSignature); System.out.println(AuthorizationHeader); return AuthorizationHeader; } public String GetCanonicalizedHeaders(HttpRequest request) { List<String> headerNameList = new ArrayList<String>(); StringBuilder sb = new StringBuilder(); // Retrieve any headers starting with , // put them in a list and sort them by value. for (Entry<String, String> entry : request.headers()) { if (entry.getKey().toLowerCase().startsWith("x-ms-")) { headerNameList.add(entry.getKey().toLowerCase() + ":" + entry.getValue() + "\n"); } } Collections.sort(headerNameList, (a, b) -> a.compareToIgnoreCase(b)); for (String headerstring : headerNameList) { sb.append(headerstring); } return sb.toString(); } public String GetCanonicalizedResource(String resourceUrl, String storageAccountName) { StringBuilder builder = new StringBuilder("/"); builder.append(storageAccountName); builder.append(resourceUrl); return builder.toString(); } public synchronized String computeHmac256(String storage_key, final String value) throws InvalidKeyException { byte[] utf8Bytes = null; try { utf8Bytes = value.getBytes("UTF-8"); if (hmacSha256 == null) { // Initializes the HMAC-SHA256 Mac and SecretKey. try { hmacSha256 = Mac.getInstance("HmacSHA256"); } catch (final NoSuchAlgorithmException e) { throw new IllegalArgumentException(); } hmacSha256.init(new SecretKeySpec(storage.netty.Base64.decode(storage_key), "HmacSHA256")); } return storage.netty.Base64.encode(hmacSha256.doFinal(utf8Bytes)); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException(e); } return null; } String randomString(int len) { StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) sb.append(AB.charAt(rnd.nextInt(AB.length()))); return sb.toString(); } private static void setContentTypeHeader(HttpRequest request, File file) { MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); request.headers().set(HttpHeaderNames.CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath())); } }