1 /*
   2  * Copyright (c) 1997, 2013, 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 
  26 package com.sun.xml.internal.ws.transport.http;
  27 
  28 import com.oracle.webservices.internal.api.message.BasePropertySet;
  29 import com.oracle.webservices.internal.api.message.PropertySet;
  30 import com.sun.istack.internal.NotNull;
  31 import com.sun.istack.internal.Nullable;
  32 import com.sun.xml.internal.ws.api.message.Packet;
  33 import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate;
  34 
  35 import javax.xml.ws.WebServiceContext;
  36 import java.io.IOException;
  37 import java.io.InputStream;
  38 import java.io.OutputStream;
  39 import java.net.HttpURLConnection;
  40 import java.security.Principal;
  41 import java.util.Collections;
  42 import java.util.List;
  43 import java.util.Map;
  44 import java.util.Set;
  45 
  46 
  47 /**
  48  * The view of an HTTP exchange from the point of view of JAX-WS.
  49  *
  50  * <p>
  51  * Different HTTP server layer uses different implementations of this class
  52  * so that JAX-WS can be shielded from individuality of such layers.
  53  * This is an interface implemented as an abstract class, so that
  54  * future versions of the JAX-WS RI can add new methods.
  55  *
  56  * <p>
  57  * This class extends {@link PropertySet} so that a transport can
  58  * expose its properties to the application and pipes. (This object
  59  * will be added to {@link Packet#addSatellite(PropertySet)}.)
  60  *
  61  * @author Jitendra Kotamraju
  62  */
  63 public abstract class WSHTTPConnection extends BasePropertySet {
  64 
  65     public static final int OK=200;
  66     public static final int ONEWAY=202;
  67     public static final int UNSUPPORTED_MEDIA=415;
  68     public static final int MALFORMED_XML=400;
  69     public static final int INTERNAL_ERR=500;
  70 
  71     /**
  72      * Overwrites all the HTTP response headers written thus far.
  73      *
  74      * <p>
  75      * The implementation should copy the contents of the {@link Map},
  76      * rather than retaining a reference. The {@link Map} passed as a
  77      * parameter may change after this method is invoked.
  78      *
  79      * <p>
  80      * This method may be called repeatedly, although in normal use
  81      * case that's rare (so the implementation is encourage to take
  82      * advantage of this usage pattern to improve performance, if possible.)
  83      *
  84      * <p>
  85      * Initially, no header is set.
  86      *
  87      * <p>
  88      * This parameter is usually exposed to {@link WebServiceContext}
  89      * as {@link Packet#OUTBOUND_TRANSPORT_HEADERS}, and thus it
  90      * should ignore {@code Content-Type} and {@code Content-Length} headers.
  91      *
  92      * @param headers
  93      *      See {@link HttpURLConnection#getHeaderFields()} for the format.
  94      *      This parameter may not be null, but since the user application
  95      *      code may invoke this method, a graceful error checking with
  96      *      an helpful error message should be provided if it's actually null.
  97      * @see #setContentTypeResponseHeader(String)
  98      */
  99     public abstract void setResponseHeaders(@NotNull Map<String,List<String>> headers);
 100 
 101     public void setResponseHeader(String key, String value) {
 102         setResponseHeader(key, Collections.singletonList(value));
 103     }
 104 
 105     public abstract void setResponseHeader(String key, List<String> value);
 106 
 107     /**
 108      * Sets the {@code "Content-Type"} header.
 109      *
 110      * <p>
 111      * If the Content-Type header has already been set, this method will overwrite
 112      * the previously set value. If not, this method adds it.
 113      *
 114      * <p>
 115      * Note that this method and {@link #setResponseHeaders(java.util.Map)}
 116      * may be invoked in any arbitrary order.
 117      *
 118      * @param value
 119      *      strings like {@code "application/xml; charset=UTF-8"} or
 120      *      {@code "image/jpeg"}.
 121      */
 122     public abstract void setContentTypeResponseHeader(@NotNull String value);
 123 
 124     /**
 125      * Sets the HTTP response code like {@link #OK}.
 126      *
 127      * <p>
 128      * While JAX-WS processes a {@link WSHTTPConnection}, it
 129      * will at least call this method once to set a valid HTTP response code.
 130      * Note that this method may be invoked multiple times (from user code),
 131      * so do not consider the value to be final until {@link #getOutput()}
 132      * is invoked.
 133      */
 134 
 135     public abstract void setStatus(int status);
 136 
 137     /**
 138      * Gets the last value set by {@link #setStatus(int)}.
 139      *
 140      * @return
 141      *      if {@link #setStatus(int)} has not been invoked yet,
 142      *      return 0.
 143      */
 144     // I know this is ugly method!
 145     public abstract int getStatus();
 146 
 147     /**
 148      * Transport's underlying input stream.
 149      *
 150      * <p>
 151      * This method will be invoked at most once by the JAX-WS RI to
 152      * read the request body. If there's no request body, this method
 153      * should return an empty {@link InputStream}.
 154      *
 155      * @return
 156      *      the stream from which the request body will be read.
 157      */
 158     public abstract @NotNull InputStream getInput() throws IOException;
 159 
 160     /**
 161      * Transport's underlying output stream
 162      *
 163      * <p>
 164      * This method will be invoked exactly once by the JAX-WS RI
 165      * to start writing the response body (unless the processing aborts abnormally.)
 166      * Even if there's no response body to write, this method will
 167      * still be invoked only to be closed immediately.
 168      *
 169      * <p>
 170      * Once this method is called, the status code and response
 171      * headers will never change (IOW {@link #setStatus(int)},
 172      * {@link #setResponseHeaders}, and {@link #setContentTypeResponseHeader(String)}
 173      * will never be invoked.
 174      */
 175     public abstract @NotNull OutputStream getOutput() throws IOException;
 176 
 177     /**
 178      * Returns the {@link WebServiceContextDelegate} for this connection.
 179      */
 180     public abstract @NotNull WebServiceContextDelegate getWebServiceContextDelegate();
 181 
 182     /**
 183      * HTTP request method, such as "GET" or "POST".
 184      */
 185     public abstract @NotNull String getRequestMethod();
 186 
 187     /**
 188      * HTTP request headers.
 189      *
 190      * @deprecated
 191      *      This is a potentially expensive operation.
 192      *      Programs that want to access HTTP headers should consider using
 193      *      other methods such as {@link #getRequestHeader(String)}.
 194      *
 195      * @return
 196      *      can be empty but never null.
 197      */
 198     public abstract @NotNull Map<String,List<String>> getRequestHeaders();
 199 
 200     /**
 201      * HTTP request header names.
 202      *
 203      * @deprecated
 204      *      This is a potentially expensive operation.
 205      *      Programs that want to access HTTP headers should consider using
 206      *      other methods such as {@link #getRequestHeader(String)}.
 207      *
 208      * @return
 209      *      can be empty but never null.
 210      */
 211     public abstract @NotNull Set<String> getRequestHeaderNames();
 212 
 213     /**
 214      * @return
 215      *      HTTP response headers.
 216      */
 217     public abstract Map<String,List<String>> getResponseHeaders();
 218 
 219     /**
 220      * Gets an HTTP request header.
 221      *
 222      * <p>
 223      * if multiple headers are present, this method returns one of them.
 224      * (The implementation is free to choose which one it returns.)
 225      *
 226      * @return
 227      *      null if no header exists.
 228      */
 229     public abstract @Nullable String getRequestHeader(@NotNull String headerName);
 230 
 231     /**
 232      * Gets an HTTP request header.
 233      *
 234      * @return
 235      *      null if no header exists.
 236      */
 237     public abstract @Nullable List<String> getRequestHeaderValues(@NotNull String headerName);
 238 
 239     /**
 240      * HTTP Query string, such as "foo=bar", or null if none exists.
 241      */
 242     public abstract @Nullable String getQueryString();
 243 
 244     /**
 245      * Extra portion of the request URI after the end of the expected address of the service
 246      * but before the query string
 247      */
 248     public abstract @Nullable String getPathInfo();
 249 
 250     /**
 251      * Requested path. A string like "/foo/bar/baz"
 252      */
 253     public abstract @NotNull String getRequestURI();
 254 
 255     /**
 256      * Requested scheme, e.g. "http" or "https"
 257      */
 258     public abstract @NotNull String getRequestScheme();
 259 
 260     /**
 261      * Server name
 262      */
 263     public abstract @NotNull String getServerName();
 264 
 265     /**
 266      * Server port
 267      */
 268     public abstract int getServerPort();
 269 
 270     /**
 271      * Portion of the request URI that groups related service addresses.  The value, if non-empty, will
 272      * always begin with '/', but will never end with '/'.  Environments that do not support
 273      * context paths must return an empty string.
 274      */
 275     public @NotNull String getContextPath() {
 276         return "";
 277     }
 278 
 279     /**
 280      * Environment specific context , if available
 281      */
 282     public Object getContext() {
 283         return null;
 284     }
 285 
 286     /**
 287      * Gets the absolute URL up to the context path.
 288      * @return
 289      *      String like "http://myhost/myapp"
 290      * @since 2.1.2
 291      */
 292     public @NotNull String getBaseAddress() {
 293         throw new UnsupportedOperationException();
 294     }
 295 
 296     /**
 297      * Whether connection is HTTPS or not
 298      *
 299      * @return if the received request is on HTTPS, return true
 300      *         else false
 301      */
 302     public abstract boolean isSecure();
 303 
 304     /**
 305      * User principal associated with the request
 306      *
 307      * @return user principal
 308      */
 309     public Principal getUserPrincipal() {
 310         return null;
 311     }
 312 
 313     /**
 314      * Whether user associated with the request holds the given role
 315      *
 316      * @param role Role to check
 317      * @return if the caller holds the role
 318      */
 319     public boolean isUserInRole(String role) {
 320         return false;
 321     }
 322 
 323     /**
 324      * Gets request metadata attribute
 325      * @param key Request metadata key
 326      * @return Value of metadata attribute or null, if no value present
 327      */
 328     public Object getRequestAttribute(String key) {
 329         return null;
 330     }
 331 
 332     private volatile boolean closed;
 333 
 334     /**
 335      * Close the connection
 336      */
 337     public void close() {
 338         this.closed = true;
 339     }
 340 
 341     /**
 342      * Retuns whether connection is closed or not.
 343      */
 344     public boolean isClosed() {
 345         return closed;
 346     }
 347 
 348     /**
 349      * Subclasses are expected to override
 350      *
 351      * @return a {@link String} containing the protocol name and version number
 352      */
 353     public String getProtocol() {
 354         return "HTTP/1.1";
 355     }
 356 
 357     /**
 358      * Subclasses are expected to override
 359      *
 360      * @since JAX-WS RI 2.2.2
 361      * @return value of given cookie
 362      */
 363     public String getCookie(String name) {
 364         return null;
 365     }
 366 
 367     /**
 368      * Subclasses are expected to override
 369      *
 370      *
 371      * @since JAX-WS RI 2.2.2
 372      */
 373     public void setCookie(String name, String value) {
 374     }
 375 
 376     /**
 377      * Subclasses are expected to override
 378      */
 379     public void setContentLengthResponseHeader(int value) {
 380     }
 381 
 382 }