Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java
38831 views
/*1* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.timestamp;2627import java.io.BufferedInputStream;28import java.io.DataOutputStream;29import java.io.EOFException;30import java.io.IOException;31import java.net.URI;32import java.net.URL;33import java.net.HttpURLConnection;34import java.util.*;3536import sun.misc.IOUtils;37import sun.security.util.Debug;3839/**40* A timestamper that communicates with a Timestamping Authority (TSA)41* over HTTP.42* It supports the Time-Stamp Protocol defined in:43* <a href="http://www.ietf.org/rfc/rfc3161.txt">RFC 3161</a>.44*45* @since 1.546* @author Vincent Ryan47*/4849public class HttpTimestamper implements Timestamper {5051private static final int CONNECT_TIMEOUT = 15000; // 15 seconds5253// The MIME type for a timestamp query54private static final String TS_QUERY_MIME_TYPE =55"application/timestamp-query";5657// The MIME type for a timestamp reply58private static final String TS_REPLY_MIME_TYPE =59"application/timestamp-reply";6061private static final Debug debug = Debug.getInstance("ts");6263/*64* HTTP URI identifying the location of the TSA65*/66private URI tsaURI = null;6768/**69* Creates a timestamper that connects to the specified TSA.70*71* @param tsa The location of the TSA. It must be an HTTP or HTTPS URI.72* @throws IllegalArgumentException if tsaURI is not an HTTP or HTTPS URI73*/74public HttpTimestamper(URI tsaURI) {75if (!tsaURI.getScheme().equalsIgnoreCase("http") &&76!tsaURI.getScheme().equalsIgnoreCase("https")) {77throw new IllegalArgumentException(78"TSA must be an HTTP or HTTPS URI");79}80this.tsaURI = tsaURI;81}8283/**84* Connects to the TSA and requests a timestamp.85*86* @param tsQuery The timestamp query.87* @return The result of the timestamp query.88* @throws IOException The exception is thrown if a problem occurs while89* communicating with the TSA.90*/91public TSResponse generateTimestamp(TSRequest tsQuery) throws IOException {9293HttpURLConnection connection =94(HttpURLConnection) tsaURI.toURL().openConnection();95connection.setDoOutput(true);96connection.setUseCaches(false); // ignore cache97connection.setRequestProperty("Content-Type", TS_QUERY_MIME_TYPE);98connection.setRequestMethod("POST");99// Avoids the "hang" when a proxy is required but none has been set.100connection.setConnectTimeout(CONNECT_TIMEOUT);101102if (debug != null) {103Set<Map.Entry<String, List<String>>> headers =104connection.getRequestProperties().entrySet();105debug.println(connection.getRequestMethod() + " " + tsaURI +106" HTTP/1.1");107for (Map.Entry<String, List<String>> e : headers) {108debug.println(" " + e);109}110debug.println();111}112connection.connect(); // No HTTP authentication is performed113114// Send the request115DataOutputStream output = null;116try {117output = new DataOutputStream(connection.getOutputStream());118byte[] request = tsQuery.encode();119output.write(request, 0, request.length);120output.flush();121if (debug != null) {122debug.println("sent timestamp query (length=" +123request.length + ")");124}125} finally {126if (output != null) {127output.close();128}129}130131// Receive the reply132BufferedInputStream input = null;133byte[] replyBuffer = null;134try {135input = new BufferedInputStream(connection.getInputStream());136if (debug != null) {137String header = connection.getHeaderField(0);138debug.println(header);139int i = 1;140while ((header = connection.getHeaderField(i)) != null) {141String key = connection.getHeaderFieldKey(i);142debug.println(" " + ((key==null) ? "" : key + ": ") +143header);144i++;145}146debug.println();147}148verifyMimeType(connection.getContentType());149150int clen = connection.getContentLength();151replyBuffer = IOUtils.readAllBytes(input);152if (clen != -1 && replyBuffer.length != clen)153throw new EOFException("Expected:" + clen +154", read:" + replyBuffer.length);155156if (debug != null) {157debug.println("received timestamp response (length=" +158replyBuffer.length + ")");159}160} finally {161if (input != null) {162input.close();163}164}165return new TSResponse(replyBuffer);166}167168/*169* Checks that the MIME content type is a timestamp reply.170*171* @param contentType The MIME content type to be checked.172* @throws IOException The exception is thrown if a mismatch occurs.173*/174private static void verifyMimeType(String contentType) throws IOException {175if (! TS_REPLY_MIME_TYPE.equalsIgnoreCase(contentType)) {176throw new IOException("MIME Content-Type is not " +177TS_REPLY_MIME_TYPE);178}179}180}181182183