1/*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.incubator.http;
27
28import java.io.IOException;
29import java.net.URI;
30import java.nio.ByteBuffer;
31import java.util.concurrent.CompletableFuture;
32import javax.net.ssl.SSLParameters;
33import jdk.incubator.http.internal.common.Log;
34import jdk.incubator.http.internal.websocket.RawChannel;
35
36/**
37 * The implementation class for HttpResponse
38 */
39class HttpResponseImpl<T> extends HttpResponse<T> implements RawChannel.Provider {
40
41    final int responseCode;
42    final Exchange<T> exchange;
43    final HttpRequest initialRequest;
44    final HttpRequestImpl finalRequest;
45    final HttpHeaders headers;
46    //final HttpHeaders trailers;
47    final SSLParameters sslParameters;
48    final URI uri;
49    final HttpClient.Version version;
50    //final AccessControlContext acc;
51    RawChannel rawchan;
52    final HttpConnection connection;
53    final Stream<T> stream;
54    final T body;
55
56    public HttpResponseImpl(HttpRequest initialRequest,
57                            Response response,
58                            T body, Exchange<T> exch) {
59        this.responseCode = response.statusCode();
60        this.exchange = exch;
61        this.initialRequest = initialRequest;
62        this.finalRequest = exchange.request();
63        this.headers = response.headers();
64        //this.trailers = trailers;
65        this.sslParameters = exch.client().sslParameters().orElse(null);
66        this.uri = finalRequest.uri();
67        this.version = response.version();
68        this.connection = exch.exchImpl.connection();
69        this.stream = null;
70        this.body = body;
71    }
72
73    // A response to a PUSH_PROMISE
74    public HttpResponseImpl(Response response,
75                            HttpRequestImpl pushRequest,
76                            ImmutableHeaders headers,
77                            Stream<T> stream,
78                            SSLParameters sslParameters,
79                            T body) {
80        this.responseCode = response.statusCode();
81        this.exchange = null;
82        this.initialRequest = null; // ## fix this
83        this.finalRequest = pushRequest;
84        this.headers = headers;
85        //this.trailers = null;
86        this.sslParameters = sslParameters;
87        this.uri = finalRequest.uri(); // TODO: take from headers
88        this.version = HttpClient.Version.HTTP_2;
89        this.connection = stream.connection();
90        this.stream = stream;
91        this.body = body;
92    }
93
94    private ExchangeImpl<?> exchangeImpl() {
95        return exchange != null ? exchange.exchImpl : stream;
96    }
97
98    @Override
99    public int statusCode() {
100        return responseCode;
101    }
102
103    @Override
104    public HttpRequest request() {
105        return initialRequest;
106    }
107
108    @Override
109    public HttpRequest finalRequest() {
110        return finalRequest;
111    }
112
113    @Override
114    public HttpHeaders headers() {
115        return headers;
116    }
117
118    @Override
119    public T body() {
120        return body;
121    }
122
123    @Override
124    public SSLParameters sslParameters() {
125        return sslParameters;
126    }
127
128    @Override
129    public URI uri() {
130        return uri;
131    }
132
133    @Override
134    public HttpClient.Version version() {
135        return version;
136    }
137    // keepalive flag determines whether connection is closed or kept alive
138    // by reading/skipping data
139
140    /**
141     * Returns a RawChannel that may be used for WebSocket protocol.
142     * @implNote This implementation does not support RawChannel over
143     *           HTTP/2 connections.
144     * @return a RawChannel that may be used for WebSocket protocol.
145     * @throws UnsupportedOperationException if getting a RawChannel over
146     *         this connection is not supported.
147     * @throws IOException if an I/O exception occurs while retrieving
148     *         the channel.
149     */
150    @Override
151    public synchronized RawChannel rawChannel() throws IOException {
152        if (rawchan == null) {
153            ExchangeImpl<?> exchImpl = exchangeImpl();
154            if (!(exchImpl instanceof Http1Exchange)) {
155                // RawChannel is only used for WebSocket - and WebSocket
156                // is not supported over HTTP/2 yet, so we should not come
157                // here. Getting a RawChannel over HTTP/2 might be supported
158                // in the future, but it would entail retrieving any left over
159                // bytes that might have been read but not consumed by the
160                // HTTP/2 connection.
161                throw new UnsupportedOperationException("RawChannel is not supported over HTTP/2");
162            }
163            // Http1Exchange may have some remaining bytes in its
164            // internal buffer.
165            final ByteBuffer remaining =((Http1Exchange<?>)exchImpl).getBuffer();
166            rawchan = new RawChannelImpl(exchange.client(), connection, remaining);
167        }
168        return rawchan;
169    }
170
171    @Override
172    public CompletableFuture<HttpHeaders> trailers() {
173        throw new UnsupportedOperationException("Not supported yet.");
174    }
175
176    static void logResponse(Response r) {
177        if (!Log.requests()) {
178            return;
179        }
180        StringBuilder sb = new StringBuilder();
181        String method = r.request().method();
182        URI uri = r.request().uri();
183        String uristring = uri == null ? "" : uri.toString();
184        sb.append('(')
185                .append(method)
186                .append(" ")
187                .append(uristring)
188                .append(") ")
189                .append(r.statusCode());
190        Log.logResponse(sb.toString());
191    }
192}
193