mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 04:24:49 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Authenticator represents an implementation of an HTTP authentication
|
||||
* mechanism. Sub-classes provide implementations of specific mechanisms
|
||||
* such as Digest or Basic auth. Instances are invoked to provide verification
|
||||
* of the authentication information provided in all incoming requests.
|
||||
* Note. This implies that any caching of credentials or other authentication
|
||||
* information must be done outside of this class.
|
||||
*/
|
||||
public abstract class Authenticator {
|
||||
|
||||
/**
|
||||
* Base class for return type from authenticate() method
|
||||
*/
|
||||
public abstract static class Result {}
|
||||
|
||||
/**
|
||||
* Indicates an authentication failure. The authentication
|
||||
* attempt has completed.
|
||||
*/
|
||||
public static class Failure extends Result {
|
||||
|
||||
private int responseCode;
|
||||
|
||||
public Failure (int responseCode) {
|
||||
this.responseCode = responseCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the response code to send to the client
|
||||
*/
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates an authentication has succeeded and the
|
||||
* authenticated user principal can be acquired by calling
|
||||
* getPrincipal().
|
||||
*/
|
||||
public static class Success extends Result {
|
||||
private HttpPrincipal principal;
|
||||
|
||||
public Success (HttpPrincipal p) {
|
||||
principal = p;
|
||||
}
|
||||
/**
|
||||
* returns the authenticated user Principal
|
||||
*/
|
||||
public HttpPrincipal getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates an authentication must be retried. The
|
||||
* response code to be sent back is as returned from
|
||||
* getResponseCode(). The Authenticator must also have
|
||||
* set any necessary response headers in the given HttpExchange
|
||||
* before returning this Retry object.
|
||||
*/
|
||||
public static class Retry extends Result {
|
||||
|
||||
private int responseCode;
|
||||
|
||||
public Retry (int responseCode) {
|
||||
this.responseCode = responseCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the response code to send to the client
|
||||
*/
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called to authenticate each incoming request. The implementation
|
||||
* must return a Failure, Success or Retry object as appropriate :-
|
||||
* <p>
|
||||
* Failure means the authentication has completed, but has failed
|
||||
* due to invalid credentials.
|
||||
* <p>
|
||||
* Sucess means that the authentication
|
||||
* has succeeded, and a Principal object representing the user
|
||||
* can be retrieved by calling Sucess.getPrincipal() .
|
||||
* <p>
|
||||
* Retry means that another HTTP exchange is required. Any response
|
||||
* headers needing to be sent back to the client are set in the
|
||||
* given HttpExchange. The response code to be returned must be provided
|
||||
* in the Retry object. Retry may occur multiple times.
|
||||
*/
|
||||
public abstract Result authenticate (HttpExchange exch);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* BasicAuthenticator provides an implementation of HTTP Basic
|
||||
* authentication. It is an abstract class and must be extended
|
||||
* to provide an implementation of {@link #checkCredentials(String,String)}
|
||||
* which is called to verify each incoming request.
|
||||
*/
|
||||
public abstract class BasicAuthenticator extends Authenticator {
|
||||
|
||||
protected String realm;
|
||||
|
||||
/**
|
||||
* Creates a BasicAuthenticator for the given HTTP realm
|
||||
* @param realm The HTTP Basic authentication realm
|
||||
* @throws NullPointerException if the realm is an empty string
|
||||
*/
|
||||
public BasicAuthenticator (String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the realm this BasicAuthenticator was created with
|
||||
* @return the authenticator's realm string.
|
||||
*/
|
||||
public String getRealm () {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public Result authenticate (HttpExchange t)
|
||||
{
|
||||
Headers rmap = t.getRequestHeaders();
|
||||
/*
|
||||
* look for auth token
|
||||
*/
|
||||
String auth = rmap.getFirst ("Authorization");
|
||||
if (auth == null) {
|
||||
Headers map = t.getResponseHeaders();
|
||||
map.set ("WWW-Authenticate", "Basic realm=" + "\""+realm+"\"");
|
||||
return new Authenticator.Retry (401);
|
||||
}
|
||||
int sp = auth.indexOf (' ');
|
||||
if (sp == -1 || !auth.substring(0, sp).equals ("Basic")) {
|
||||
return new Authenticator.Failure (401);
|
||||
}
|
||||
byte[] b = Base64.getDecoder().decode(auth.substring(sp+1));
|
||||
String userpass = new String (b);
|
||||
int colon = userpass.indexOf (':');
|
||||
String uname = userpass.substring (0, colon);
|
||||
String pass = userpass.substring (colon+1);
|
||||
|
||||
if (checkCredentials (uname, pass)) {
|
||||
return new Authenticator.Success (
|
||||
new HttpPrincipal (
|
||||
uname, realm
|
||||
)
|
||||
);
|
||||
} else {
|
||||
/* reject the request again with 401 */
|
||||
|
||||
Headers map = t.getResponseHeaders();
|
||||
map.set ("WWW-Authenticate", "Basic realm=" + "\""+realm+"\"");
|
||||
return new Authenticator.Failure(401);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called for each incoming request to verify the
|
||||
* given name and password in the context of this
|
||||
* Authenticator's realm. Any caching of credentials
|
||||
* must be done by the implementation of this method
|
||||
* @param username the username from the request
|
||||
* @param password the password from the request
|
||||
* @return <code>true</code> if the credentials are valid,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public abstract boolean checkCredentials (String username, String password);
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A filter used to pre- and post-process incoming requests. Pre-processing occurs
|
||||
* before the application's exchange handler is invoked, and post-processing
|
||||
* occurs after the exchange handler returns. Filters
|
||||
* are organised in chains, and are associated with HttpContext instances.
|
||||
* <p>
|
||||
* Each Filter in the chain, invokes the next filter within its own
|
||||
* doFilter() implementation. The final Filter in the chain invokes the applications
|
||||
* exchange handler.
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class Filter {
|
||||
|
||||
protected Filter () {}
|
||||
|
||||
/**
|
||||
* a chain of filters associated with a HttpServer.
|
||||
* Each filter in the chain is given one of these
|
||||
* so it can invoke the next filter in the chain
|
||||
*/
|
||||
public static class Chain {
|
||||
/* the last element in the chain must invoke the users
|
||||
* handler
|
||||
*/
|
||||
private ListIterator<Filter> iter;
|
||||
private HttpHandler handler;
|
||||
|
||||
public Chain (List<Filter> filters, HttpHandler handler) {
|
||||
iter = filters.listIterator();
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* calls the next filter in the chain, or else
|
||||
* the users exchange handler, if this is the
|
||||
* final filter in the chain. The Filter may decide
|
||||
* to terminate the chain, by not calling this method.
|
||||
* In this case, the filter <b>must</b> send the
|
||||
* response to the request, because the application's
|
||||
* exchange handler will not be invoked.
|
||||
* @param exchange the HttpExchange
|
||||
* @throws IOException let exceptions pass up the stack
|
||||
* @throws NullPointerException if exchange is {@code null}
|
||||
*/
|
||||
public void doFilter (HttpExchange exchange) throws IOException {
|
||||
if (!iter.hasNext()) {
|
||||
handler.handle (exchange);
|
||||
} else {
|
||||
Filter f = iter.next();
|
||||
f.doFilter (exchange, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks this filter to pre/post-process the given exchange. The filter
|
||||
* can:
|
||||
* <ul><li>examine or modify the request headers</li>
|
||||
* <li>filter the request body or the response body, by creating suitable
|
||||
* filter streams and calling
|
||||
* {@link HttpExchange#setStreams(InputStream,OutputStream)}</li>
|
||||
* <li>set attribute Objects in the exchange, which other filters or the
|
||||
* exchange handler can access.</li>
|
||||
* <li>decide to either<ol>
|
||||
* <li>invoke the next filter in the chain, by calling
|
||||
* {@link Filter.Chain#doFilter(HttpExchange)}</li>
|
||||
* <li>terminate the chain of invocation, by <b>not</b> calling
|
||||
* {@link Filter.Chain#doFilter(HttpExchange)}</li></ol>
|
||||
* <li>if option 1. above taken, then when doFilter() returns all subsequent
|
||||
* filters in the Chain have been called, and the response headers can be
|
||||
* examined or modified.</li>
|
||||
* <li>if option 2. above taken, then this Filter must use the HttpExchange
|
||||
* to send back an appropriate response</li></ul>
|
||||
*
|
||||
* @param exchange the {@code HttpExchange} to be filtered.
|
||||
* @param chain the Chain which allows the next filter to be invoked.
|
||||
* @throws IOException may be thrown by any filter module, and if
|
||||
* caught, must be rethrown again.
|
||||
* @throws NullPointerException if either exchange or chain are {@code null}
|
||||
*/
|
||||
public abstract void doFilter (HttpExchange exchange, Chain chain)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* returns a short description of this Filter
|
||||
* @return a string describing the Filter
|
||||
*/
|
||||
public abstract String description ();
|
||||
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* HTTP request and response headers are represented by this class which implements
|
||||
* the interface
|
||||
* {@link java.util.Map}{@literal <}{@link java.lang.String}, {@link java.util.List}
|
||||
* {@literal <}{@link java.lang.String}{@literal >>}.
|
||||
* The keys are case-insensitive Strings representing the header names and
|
||||
* the value associated with each key is
|
||||
* a {@link List}{@literal <}{@link String}{@literal >} with one
|
||||
* element for each occurrence of the header name in the request or response.
|
||||
* <p>
|
||||
* For example, if a response header instance contains
|
||||
* one key "HeaderName" with two values "value1 and value2"
|
||||
* then this object is output as two header lines:
|
||||
* <blockquote><pre>
|
||||
* HeaderName: value1
|
||||
* HeaderName: value2
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* All the normal {@link java.util.Map} methods are provided, but the following
|
||||
* additional convenience methods are most likely to be used:
|
||||
* <ul>
|
||||
* <li>{@link #getFirst(String)} returns a single valued header or the first value of
|
||||
* a multi-valued header.</li>
|
||||
* <li>{@link #add(String,String)} adds the given header value to the list for the given key</li>
|
||||
* <li>{@link #set(String,String)} sets the given header field to the single value given
|
||||
* overwriting any existing values in the value list.
|
||||
* </ul><p>
|
||||
* All methods in this class accept <code>null</code> values for keys and values. However, null
|
||||
* keys will never will be present in HTTP request headers, and will not be output/sent in response headers.
|
||||
* Null values can be represented as either a null entry for the key (i.e. the list is null) or
|
||||
* where the key has a list, but one (or more) of the list's values is null. Null values are output
|
||||
* as a header line containing the key but no associated value.
|
||||
* @since 1.6
|
||||
*/
|
||||
public class Headers implements Map<String,List<String>> {
|
||||
|
||||
HashMap<String,List<String>> map;
|
||||
|
||||
public Headers () {map = new HashMap<String,List<String>>(32);}
|
||||
|
||||
/* Normalize the key by converting to following form.
|
||||
* First char upper case, rest lower case.
|
||||
* key is presumed to be ASCII
|
||||
*/
|
||||
private String normalize (String key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
int len = key.length();
|
||||
if (len == 0) {
|
||||
return key;
|
||||
}
|
||||
char[] b = key.toCharArray();
|
||||
if (b[0] >= 'a' && b[0] <= 'z') {
|
||||
b[0] = (char)(b[0] - ('a' - 'A'));
|
||||
}
|
||||
for (int i=1; i<len; i++) {
|
||||
if (b[i] >= 'A' && b[i] <= 'Z') {
|
||||
b[i] = (char) (b[i] + ('a' - 'A'));
|
||||
}
|
||||
}
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
public int size() {return map.size();}
|
||||
|
||||
public boolean isEmpty() {return map.isEmpty();}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(key instanceof String)) {
|
||||
return false;
|
||||
}
|
||||
return map.containsKey (normalize((String)key));
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
public List<String> get(Object key) {
|
||||
return map.get(normalize((String)key));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the first value from the List of String values
|
||||
* for the given key (if at least one exists).
|
||||
* @param key the key to search for
|
||||
* @return the first string value associated with the key
|
||||
*/
|
||||
public String getFirst (String key) {
|
||||
List<String> l = map.get(normalize(key));
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
return l.get(0);
|
||||
}
|
||||
|
||||
public List<String> put(String key, List<String> value) {
|
||||
return map.put (normalize(key), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the given value to the list of headers
|
||||
* for the given key. If the mapping does not
|
||||
* already exist, then it is created
|
||||
* @param key the header name
|
||||
* @param value the header value to add to the header
|
||||
*/
|
||||
public void add (String key, String value) {
|
||||
String k = normalize(key);
|
||||
List<String> l = map.get(k);
|
||||
if (l == null) {
|
||||
l = new LinkedList<String>();
|
||||
map.put(k,l);
|
||||
}
|
||||
l.add (value);
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the given value as the sole header value
|
||||
* for the given key. If the mapping does not
|
||||
* already exist, then it is created
|
||||
* @param key the header name
|
||||
* @param value the header value to set.
|
||||
*/
|
||||
public void set (String key, String value) {
|
||||
LinkedList<String> l = new LinkedList<String>();
|
||||
l.add (value);
|
||||
put (key, l);
|
||||
}
|
||||
|
||||
|
||||
public List<String> remove(Object key) {
|
||||
return map.remove(normalize((String)key));
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends String,? extends List<String>> t) {
|
||||
map.putAll (t);
|
||||
}
|
||||
|
||||
public void clear() {map.clear();}
|
||||
|
||||
public Set<String> keySet() {return map.keySet();}
|
||||
|
||||
public Collection<List<String>> values() {return map.values();}
|
||||
|
||||
public Set<Map.Entry<String, List<String>>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {return map.equals(o);}
|
||||
|
||||
public int hashCode() {return map.hashCode();}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* HttpContext represents a mapping between the root URI path of an application
|
||||
* to a {@link HttpHandler} which is invoked to handle requests destined
|
||||
* for that path on the associated HttpServer or HttpsServer.
|
||||
* <p>
|
||||
* HttpContext instances are created by the create methods in HttpServer
|
||||
* and HttpsServer
|
||||
* <p>
|
||||
* A chain of {@link Filter} objects can be added to a HttpContext. All exchanges processed by the
|
||||
* context can be pre- and post-processed by each Filter in the chain.
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class HttpContext {
|
||||
|
||||
protected HttpContext () {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the handler for this context
|
||||
* @return the HttpHandler for this context
|
||||
*/
|
||||
public abstract HttpHandler getHandler () ;
|
||||
|
||||
/**
|
||||
* Sets the handler for this context, if not already set.
|
||||
* @param h the handler to set for this context
|
||||
* @throws IllegalArgumentException if this context's handler is already set.
|
||||
* @throws NullPointerException if handler is <code>null</code>
|
||||
*/
|
||||
public abstract void setHandler (HttpHandler h) ;
|
||||
|
||||
/**
|
||||
* returns the path this context was created with
|
||||
* @return this context's path
|
||||
*/
|
||||
public abstract String getPath() ;
|
||||
|
||||
/**
|
||||
* returns the server this context was created with
|
||||
* @return this context's server
|
||||
*/
|
||||
public abstract HttpServer getServer () ;
|
||||
|
||||
/**
|
||||
* returns a mutable Map, which can be used to pass
|
||||
* configuration and other data to Filter modules
|
||||
* and to the context's exchange handler.
|
||||
* <p>
|
||||
* Every attribute stored in this Map will be visible to
|
||||
* every HttpExchange processed by this context
|
||||
*/
|
||||
public abstract Map<String,Object> getAttributes() ;
|
||||
|
||||
/**
|
||||
* returns this context's list of Filters. This is the
|
||||
* actual list used by the server when dispatching requests
|
||||
* so modifications to this list immediately affect the
|
||||
* the handling of exchanges.
|
||||
*/
|
||||
public abstract List<Filter> getFilters();
|
||||
|
||||
/**
|
||||
* Sets the Authenticator for this HttpContext. Once an authenticator
|
||||
* is establised on a context, all client requests must be
|
||||
* authenticated, and the given object will be invoked to validate each
|
||||
* request. Each call to this method replaces any previous value set.
|
||||
* @param auth the authenticator to set. If <code>null</code> then any
|
||||
* previously set authenticator is removed,
|
||||
* and client authentication will no longer be required.
|
||||
* @return the previous Authenticator, if any set, or <code>null</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public abstract Authenticator setAuthenticator (Authenticator auth);
|
||||
|
||||
/**
|
||||
* Returns the currently set Authenticator for this context
|
||||
* if one exists.
|
||||
* @return this HttpContext's Authenticator, or <code>null</code>
|
||||
* if none is set.
|
||||
*/
|
||||
public abstract Authenticator getAuthenticator ();
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class encapsulates a HTTP request received and a
|
||||
* response to be generated in one exchange. It provides methods
|
||||
* for examining the request from the client, and for building and
|
||||
* sending the response.
|
||||
* <p>
|
||||
* The typical life-cycle of a HttpExchange is shown in the sequence
|
||||
* below.
|
||||
* <ol><li>{@link #getRequestMethod()} to determine the command
|
||||
* <li>{@link #getRequestHeaders()} to examine the request headers (if needed)
|
||||
* <li>{@link #getRequestBody()} returns a {@link java.io.InputStream} for reading the request body.
|
||||
* After reading the request body, the stream is close.
|
||||
* <li>{@link #getResponseHeaders()} to set any response headers, except content-length
|
||||
* <li>{@link #sendResponseHeaders(int,long)} to send the response headers. Must be called before
|
||||
* next step.
|
||||
* <li>{@link #getResponseBody()} to get a {@link java.io.OutputStream} to send the response body.
|
||||
* When the response body has been written, the stream must be closed to terminate the exchange.
|
||||
* </ol>
|
||||
* <b>Terminating exchanges</b>
|
||||
* <br>
|
||||
* Exchanges are terminated when both the request InputStream and response OutputStream are closed.
|
||||
* Closing the OutputStream, implicitly closes the InputStream (if it is not already closed).
|
||||
* However, it is recommended
|
||||
* to consume all the data from the InputStream before closing it.
|
||||
* The convenience method {@link #close()} does all of these tasks.
|
||||
* Closing an exchange without consuming all of the request body is not an error
|
||||
* but may make the underlying TCP connection unusable for following exchanges.
|
||||
* The effect of failing to terminate an exchange is undefined, but will typically
|
||||
* result in resources failing to be freed/reused.
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public abstract class HttpExchange {
|
||||
|
||||
protected HttpExchange () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable Map containing the HTTP headers that were
|
||||
* included with this request. The keys in this Map will be the header
|
||||
* names, while the values will be a List of Strings containing each value
|
||||
* that was included (either for a header that was listed several times,
|
||||
* or one that accepts a comma-delimited list of values on a single line).
|
||||
* In either of these cases, the values for the header name will be
|
||||
* presented in the order that they were included in the request.
|
||||
* <p>
|
||||
* The keys in Map are case-insensitive.
|
||||
* @return a read-only Map which can be used to access request headers
|
||||
*/
|
||||
public abstract Headers getRequestHeaders () ;
|
||||
|
||||
/**
|
||||
* Returns a mutable Map into which the HTTP response headers can be stored
|
||||
* and which will be transmitted as part of this response. The keys in the
|
||||
* Map will be the header names, while the values must be a List of Strings
|
||||
* containing each value that should be included multiple times
|
||||
* (in the order that they should be included).
|
||||
* <p>
|
||||
* The keys in Map are case-insensitive.
|
||||
* @return a writable Map which can be used to set response headers.
|
||||
*/
|
||||
public abstract Headers getResponseHeaders () ;
|
||||
|
||||
/**
|
||||
* Get the request URI
|
||||
*
|
||||
* @return the request URI
|
||||
*/
|
||||
public abstract URI getRequestURI () ;
|
||||
|
||||
/**
|
||||
* Get the request method
|
||||
* @return the request method
|
||||
*/
|
||||
public abstract String getRequestMethod ();
|
||||
|
||||
/**
|
||||
* Get the HttpContext for this exchange
|
||||
* @return the HttpContext
|
||||
*/
|
||||
public abstract HttpContext getHttpContext ();
|
||||
|
||||
/**
|
||||
* Ends this exchange by doing the following in sequence:<ol>
|
||||
* <li>close the request InputStream, if not already closed;</li>
|
||||
* <li>close the response OutputStream, if not already closed.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public abstract void close () ;
|
||||
|
||||
/**
|
||||
* returns a stream from which the request body can be read.
|
||||
* Multiple calls to this method will return the same stream.
|
||||
* It is recommended that applications should consume (read) all of the
|
||||
* data from this stream before closing it. If a stream is closed
|
||||
* before all data has been read, then the close() call will
|
||||
* read and discard remaining data (up to an implementation specific
|
||||
* number of bytes).
|
||||
* @return the stream from which the request body can be read.
|
||||
*/
|
||||
public abstract InputStream getRequestBody () ;
|
||||
|
||||
/**
|
||||
* returns a stream to which the response body must be
|
||||
* written. {@link #sendResponseHeaders(int,long)}) must be called prior to calling
|
||||
* this method. Multiple calls to this method (for the same exchange)
|
||||
* will return the same stream. In order to correctly terminate
|
||||
* each exchange, the output stream must be closed, even if no
|
||||
* response body is being sent.
|
||||
* <p>
|
||||
* Closing this stream implicitly
|
||||
* closes the InputStream returned from {@link #getRequestBody()}
|
||||
* (if it is not already closed).
|
||||
* <P>
|
||||
* If the call to sendResponseHeaders() specified a fixed response
|
||||
* body length, then the exact number of bytes specified in that
|
||||
* call must be written to this stream. If too many bytes are written,
|
||||
* then write() will throw an IOException. If too few bytes are written
|
||||
* then the stream close() will throw an IOException. In both cases,
|
||||
* the exchange is aborted and the underlying TCP connection closed.
|
||||
* @return the stream to which the response body is written
|
||||
*/
|
||||
public abstract OutputStream getResponseBody () ;
|
||||
|
||||
|
||||
/**
|
||||
* Starts sending the response back to the client using the current set of response headers
|
||||
* and the numeric response code as specified in this method. The response body length is also specified
|
||||
* as follows. If the response length parameter is greater than zero, this specifies an exact
|
||||
* number of bytes to send and the application must send that exact amount of data.
|
||||
* If the response length parameter is {@code zero}, then chunked transfer encoding is
|
||||
* used and an arbitrary amount of data may be sent. The application terminates the
|
||||
* response body by closing the OutputStream. If response length has the value {@code -1}
|
||||
* then no response body is being sent.
|
||||
* <p>
|
||||
* If the content-length response header has not already been set then
|
||||
* this is set to the appropriate value depending on the response length parameter.
|
||||
* <p>
|
||||
* This method must be called prior to calling {@link #getResponseBody()}.
|
||||
* @param rCode the response code to send
|
||||
* @param responseLength if {@literal > 0}, specifies a fixed response
|
||||
* body length and that exact number of bytes must be written
|
||||
* to the stream acquired from getResponseBody(), or else
|
||||
* if equal to 0, then chunked encoding is used,
|
||||
* and an arbitrary number of bytes may be written.
|
||||
* if {@literal <= -1}, then no response body length is specified and
|
||||
* no response body may be written.
|
||||
* @see HttpExchange#getResponseBody()
|
||||
*/
|
||||
public abstract void sendResponseHeaders (int rCode, long responseLength) throws IOException ;
|
||||
|
||||
/**
|
||||
* Returns the address of the remote entity invoking this request
|
||||
* @return the InetSocketAddress of the caller
|
||||
*/
|
||||
public abstract InetSocketAddress getRemoteAddress ();
|
||||
|
||||
/**
|
||||
* Returns the response code, if it has already been set
|
||||
* @return the response code, if available. {@code -1} if not available yet.
|
||||
*/
|
||||
public abstract int getResponseCode ();
|
||||
|
||||
/**
|
||||
* Returns the local address on which the request was received
|
||||
* @return the InetSocketAddress of the local interface
|
||||
*/
|
||||
public abstract InetSocketAddress getLocalAddress ();
|
||||
|
||||
/**
|
||||
* Returns the protocol string from the request in the form
|
||||
* <i>protocol/majorVersion.minorVersion</i>. For example,
|
||||
* "HTTP/1.1"
|
||||
* @return the protocol string from the request
|
||||
*/
|
||||
public abstract String getProtocol ();
|
||||
|
||||
/**
|
||||
* Filter modules may store arbitrary objects with HttpExchange
|
||||
* instances as an out-of-band communication mechanism. Other Filters
|
||||
* or the exchange handler may then access these objects.
|
||||
* <p>
|
||||
* Each Filter class will document the attributes which they make
|
||||
* available.
|
||||
* @param name the name of the attribute to retrieve
|
||||
* @return the attribute object, or null if it does not exist
|
||||
* @throws NullPointerException if name is {@code null}
|
||||
*/
|
||||
public abstract Object getAttribute (String name) ;
|
||||
|
||||
/**
|
||||
* Filter modules may store arbitrary objects with HttpExchange
|
||||
* instances as an out-of-band communication mechanism. Other Filters
|
||||
* or the exchange handler may then access these objects.
|
||||
* <p>
|
||||
* Each Filter class will document the attributes which they make
|
||||
* available.
|
||||
* @param name the name to associate with the attribute value
|
||||
* @param value the object to store as the attribute value. {@code null}
|
||||
* value is permitted.
|
||||
* @throws NullPointerException if name is {@code null}
|
||||
*/
|
||||
public abstract void setAttribute (String name, Object value) ;
|
||||
|
||||
/**
|
||||
* Used by Filters to wrap either (or both) of this exchange's InputStream
|
||||
* and OutputStream, with the given filtered streams so
|
||||
* that subsequent calls to {@link #getRequestBody()} will
|
||||
* return the given {@link java.io.InputStream}, and calls to
|
||||
* {@link #getResponseBody()} will return the given
|
||||
* {@link java.io.OutputStream}. The streams provided to this
|
||||
* call must wrap the original streams, and may be (but are not
|
||||
* required to be) sub-classes of {@link java.io.FilterInputStream}
|
||||
* and {@link java.io.FilterOutputStream}.
|
||||
* @param i the filtered input stream to set as this object's inputstream,
|
||||
* or {@code null} if no change.
|
||||
* @param o the filtered output stream to set as this object's outputstream,
|
||||
* or {@code null} if no change.
|
||||
*/
|
||||
public abstract void setStreams (InputStream i, OutputStream o);
|
||||
|
||||
|
||||
/**
|
||||
* If an authenticator is set on the HttpContext that owns this exchange,
|
||||
* then this method will return the {@link HttpPrincipal} that represents
|
||||
* the authenticated user for this HttpExchange.
|
||||
* @return the HttpPrincipal, or {@code null} if no authenticator is set.
|
||||
*/
|
||||
public abstract HttpPrincipal getPrincipal ();
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A handler which is invoked to process HTTP exchanges. Each
|
||||
* HTTP exchange is handled by one of these handlers.
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface HttpHandler {
|
||||
/**
|
||||
* Handle the given request and generate an appropriate response.
|
||||
* See {@link HttpExchange} for a description of the steps
|
||||
* involved in handling an exchange.
|
||||
* @param exchange the exchange containing the request from the
|
||||
* client and used to send the response
|
||||
* @throws NullPointerException if exchange is <code>null</code>
|
||||
*/
|
||||
public abstract void handle (HttpExchange exchange) throws IOException;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* Represents a user authenticated by HTTP Basic or Digest
|
||||
* authentication.
|
||||
*/
|
||||
public class HttpPrincipal implements Principal {
|
||||
private String username, realm;
|
||||
|
||||
/**
|
||||
* creates a HttpPrincipal from the given username and realm
|
||||
* @param username The name of the user within the realm
|
||||
* @param realm The realm.
|
||||
* @throws NullPointerException if either username or realm are null
|
||||
*/
|
||||
public HttpPrincipal (String username, String realm) {
|
||||
if (username == null || realm == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.username = username;
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two HttpPrincipal. Returns <code>true</code>
|
||||
* if <i>another</i> is an instance of HttpPrincipal, and its
|
||||
* username and realm are equal to this object's username
|
||||
* and realm. Returns <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean equals (Object another) {
|
||||
if (!(another instanceof HttpPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
HttpPrincipal theother = (HttpPrincipal)another;
|
||||
return (username.equals(theother.username) &&
|
||||
realm.equals(theother.realm));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the contents of this principal in the form
|
||||
* <i>realm:username</i>
|
||||
*/
|
||||
public String getName() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the username this object was created with.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the realm this object was created with.
|
||||
*/
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a hashcode for this HttpPrincipal. This is calculated
|
||||
* as <code>(getUsername()+getRealm().hashCode()</code>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return (username+realm).hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the same string as getName()
|
||||
*/
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.security.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import javax.net.ssl.*;
|
||||
import com.sun.net.httpserver.spi.HttpServerProvider;
|
||||
|
||||
/**
|
||||
* This class implements a simple HTTP server. A HttpServer is bound to an IP address
|
||||
* and port number and listens for incoming TCP connections from clients on this address.
|
||||
* The sub-class {@link HttpsServer} implements a server which handles HTTPS requests.
|
||||
* <p>
|
||||
* One or more {@link HttpHandler} objects must be associated with a server
|
||||
* in order to process requests. Each such HttpHandler is registered
|
||||
* with a root URI path which represents the
|
||||
* location of the application or service on this server. The mapping of a handler
|
||||
* to a HttpServer is encapsulated by a {@link HttpContext} object. HttpContexts
|
||||
* are created by calling {@link #createContext(String,HttpHandler)}.
|
||||
* Any request for which no handler can be found is rejected with a 404 response.
|
||||
* Management of threads can be done external to this object by providing a
|
||||
* {@link java.util.concurrent.Executor} object. If none is provided a default
|
||||
* implementation is used.
|
||||
* <p>
|
||||
* <a id="mapping_description"></a>
|
||||
* <b>Mapping request URIs to HttpContext paths</b><p>
|
||||
* When a HTTP request is received,
|
||||
* the appropriate HttpContext (and handler) is located by finding the context
|
||||
* whose path is the longest matching prefix of the request URI's path.
|
||||
* Paths are matched literally, which means that the strings are compared
|
||||
* case sensitively, and with no conversion to or from any encoded forms.
|
||||
* For example. Given a HttpServer with the following HttpContexts configured.
|
||||
* <table class="striped"><caption style="display:none">description</caption>
|
||||
* <thead>
|
||||
* <tr><th scope="col"><i>Context</i></th><th scope="col"><i>Context path</i></th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><th scope="row">ctx1</th><td>"/"</td></tr>
|
||||
* <tr><th scope="row">ctx2</th><td>"/apps/"</td></tr>
|
||||
* <tr><th scope="row">ctx3</th><td>"/apps/foo/"</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* the following table shows some request URIs and which, if any context they would
|
||||
* match with.
|
||||
* <table class="striped"><caption style="display:none">description</caption>
|
||||
* <thead>
|
||||
* <tr><th scope="col"><i>Request URI</i></th><th scope="col"><i>Matches context</i></th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><th scope="row">"http://foo.com/apps/foo/bar"</th><td>ctx3</td></tr>
|
||||
* <tr><th scope="row">"http://foo.com/apps/Foo/bar"</th><td>no match, wrong case</td></tr>
|
||||
* <tr><th scope="row">"http://foo.com/apps/app1"</th><td>ctx2</td></tr>
|
||||
* <tr><th scope="row">"http://foo.com/foo"</th><td>ctx1</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* <b>Note about socket backlogs</b><p>
|
||||
* When binding to an address and port number, the application can also specify an integer
|
||||
* <i>backlog</i> parameter. This represents the maximum number of incoming TCP connections
|
||||
* which the system will queue internally. Connections are queued while they are waiting to
|
||||
* be accepted by the HttpServer. When the limit is reached, further connections may be
|
||||
* rejected (or possibly ignored) by the underlying TCP implementation. Setting the right
|
||||
* backlog value is a compromise between efficient resource usage in the TCP layer (not setting
|
||||
* it too high) and allowing adequate throughput of incoming requests (not setting it too low).
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public abstract class HttpServer {
|
||||
|
||||
/**
|
||||
*/
|
||||
protected HttpServer () {
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a HttpServer instance which is initially not bound to any local address/port.
|
||||
* The HttpServer is acquired from the currently installed {@link HttpServerProvider}
|
||||
* The server must be bound using {@link #bind(InetSocketAddress,int)} before it can be used.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static HttpServer create () throws IOException {
|
||||
return create (null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>HttpServer</code> instance which will bind to the
|
||||
* specified {@link java.net.InetSocketAddress} (IP address and port number)
|
||||
*
|
||||
* A maximum backlog can also be specified. This is the maximum number of
|
||||
* queued incoming connections to allow on the listening socket.
|
||||
* Queued TCP connections exceeding this limit may be rejected by the TCP implementation.
|
||||
* The HttpServer is acquired from the currently installed {@link HttpServerProvider}
|
||||
*
|
||||
* @param addr the address to listen on, if <code>null</code> then bind() must be called
|
||||
* to set the address
|
||||
* @param backlog the socket backlog. If this value is less than or equal to zero,
|
||||
* then a system default value is used.
|
||||
* @throws BindException if the server cannot bind to the requested address,
|
||||
* or if the server is already bound.
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
public static HttpServer create (
|
||||
InetSocketAddress addr, int backlog
|
||||
) throws IOException {
|
||||
HttpServerProvider provider = HttpServerProvider.provider();
|
||||
return provider.createHttpServer (addr, backlog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a currently unbound HttpServer to the given address and port number.
|
||||
* A maximum backlog can also be specified. This is the maximum number of
|
||||
* queued incoming connections to allow on the listening socket.
|
||||
* Queued TCP connections exceeding this limit may be rejected by the TCP implementation.
|
||||
* @param addr the address to listen on
|
||||
* @param backlog the socket backlog. If this value is less than or equal to zero,
|
||||
* then a system default value is used.
|
||||
* @throws BindException if the server cannot bind to the requested address or if the server
|
||||
* is already bound.
|
||||
* @throws NullPointerException if addr is <code>null</code>
|
||||
*/
|
||||
public abstract void bind (InetSocketAddress addr, int backlog) throws IOException;
|
||||
|
||||
/**
|
||||
* Starts this server in a new background thread. The background thread
|
||||
* inherits the priority, thread group and context class loader
|
||||
* of the caller.
|
||||
*/
|
||||
public abstract void start () ;
|
||||
|
||||
/**
|
||||
* sets this server's {@link java.util.concurrent.Executor} object. An
|
||||
* Executor must be established before {@link #start()} is called.
|
||||
* All HTTP requests are handled in tasks given to the executor.
|
||||
* If this method is not called (before start()) or if it is
|
||||
* called with a <code>null</code> Executor, then
|
||||
* a default implementation is used, which uses the thread
|
||||
* which was created by the {@link #start()} method.
|
||||
* @param executor the Executor to set, or <code>null</code> for default
|
||||
* implementation
|
||||
* @throws IllegalStateException if the server is already started
|
||||
*/
|
||||
public abstract void setExecutor (Executor executor);
|
||||
|
||||
|
||||
/**
|
||||
* returns this server's Executor object if one was specified with
|
||||
* {@link #setExecutor(Executor)}, or <code>null</code> if none was
|
||||
* specified.
|
||||
* @return the Executor established for this server or <code>null</code> if not set.
|
||||
*/
|
||||
public abstract Executor getExecutor () ;
|
||||
|
||||
/**
|
||||
* stops this server by closing the listening socket and disallowing
|
||||
* any new exchanges from being processed. The method will then block
|
||||
* until all current exchange handlers have completed or else when
|
||||
* approximately <i>delay</i> seconds have elapsed (whichever happens
|
||||
* sooner). Then, all open TCP connections are closed, the background
|
||||
* thread created by start() exits, and the method returns.
|
||||
* Once stopped, a HttpServer cannot be re-used.
|
||||
*
|
||||
* @param delay the maximum time in seconds to wait until exchanges have finished.
|
||||
* @throws IllegalArgumentException if delay is less than zero.
|
||||
*/
|
||||
public abstract void stop (int delay);
|
||||
|
||||
/**
|
||||
* Creates a HttpContext. A HttpContext represents a mapping from a
|
||||
* URI path to a exchange handler on this HttpServer. Once created, all requests
|
||||
* received by the server for the path will be handled by calling
|
||||
* the given handler object. The context is identified by the path, and
|
||||
* can later be removed from the server using this with the {@link #removeContext(String)} method.
|
||||
* <p>
|
||||
* The path specifies the root URI path for this context. The first character of path must be
|
||||
* '/'. <p>
|
||||
* The class overview describes how incoming request URIs are <a href="#mapping_description">mapped</a>
|
||||
* to HttpContext instances.
|
||||
* @param path the root URI path to associate the context with
|
||||
* @param handler the handler to invoke for incoming requests.
|
||||
* @throws IllegalArgumentException if path is invalid, or if a context
|
||||
* already exists for this path
|
||||
* @throws NullPointerException if either path, or handler are <code>null</code>
|
||||
*/
|
||||
public abstract HttpContext createContext (String path, HttpHandler handler) ;
|
||||
|
||||
/**
|
||||
* Creates a HttpContext without initially specifying a handler. The handler must later be specified using
|
||||
* {@link HttpContext#setHandler(HttpHandler)}. A HttpContext represents a mapping from a
|
||||
* URI path to an exchange handler on this HttpServer. Once created, and when
|
||||
* the handler has been set, all requests
|
||||
* received by the server for the path will be handled by calling
|
||||
* the handler object. The context is identified by the path, and
|
||||
* can later be removed from the server using this with the {@link #removeContext(String)} method.
|
||||
* <p>
|
||||
* The path specifies the root URI path for this context. The first character of path must be
|
||||
* '/'. <p>
|
||||
* The class overview describes how incoming request URIs are <a href="#mapping_description">mapped</a>
|
||||
* to HttpContext instances.
|
||||
* @param path the root URI path to associate the context with
|
||||
* @throws IllegalArgumentException if path is invalid, or if a context
|
||||
* already exists for this path
|
||||
* @throws NullPointerException if path is <code>null</code>
|
||||
*/
|
||||
public abstract HttpContext createContext (String path) ;
|
||||
|
||||
/**
|
||||
* Removes the context identified by the given path from the server.
|
||||
* Removing a context does not affect exchanges currently being processed
|
||||
* but prevents new ones from being accepted.
|
||||
* @param path the path of the handler to remove
|
||||
* @throws IllegalArgumentException if no handler corresponding to this
|
||||
* path exists.
|
||||
* @throws NullPointerException if path is <code>null</code>
|
||||
*/
|
||||
public abstract void removeContext (String path) throws IllegalArgumentException ;
|
||||
|
||||
/**
|
||||
* Removes the given context from the server.
|
||||
* Removing a context does not affect exchanges currently being processed
|
||||
* but prevents new ones from being accepted.
|
||||
* @param context the context to remove
|
||||
* @throws NullPointerException if context is <code>null</code>
|
||||
*/
|
||||
public abstract void removeContext (HttpContext context) ;
|
||||
|
||||
/**
|
||||
* returns the address this server is listening on
|
||||
* @return the address/port number the server is listening on
|
||||
*/
|
||||
public abstract InetSocketAddress getAddress() ;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.security.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import javax.net.ssl.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class is used to configure the https parameters for each incoming
|
||||
* https connection on a HttpsServer. Applications need to override
|
||||
* the {@link #configure(HttpsParameters)} method in order to change
|
||||
* the default configuration.
|
||||
* <p>
|
||||
* The following <a id="example">example</a> shows how this may be done:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* SSLContext sslContext = SSLContext.getInstance (....);
|
||||
* HttpsServer server = HttpsServer.create();
|
||||
*
|
||||
* server.setHttpsConfigurator (new HttpsConfigurator(sslContext) {
|
||||
* public void configure (HttpsParameters params) {
|
||||
*
|
||||
* // get the remote address if needed
|
||||
* InetSocketAddress remote = params.getClientAddress();
|
||||
*
|
||||
* SSLContext c = getSSLContext();
|
||||
*
|
||||
* // get the default parameters
|
||||
* SSLParameters sslparams = c.getDefaultSSLParameters();
|
||||
* if (remote.equals (...) ) {
|
||||
* // modify the default set for client x
|
||||
* }
|
||||
*
|
||||
* params.setSSLParameters(sslparams);
|
||||
* }
|
||||
* });
|
||||
* </pre></blockquote>
|
||||
* @since 1.6
|
||||
*/
|
||||
public class HttpsConfigurator {
|
||||
|
||||
private SSLContext context;
|
||||
|
||||
/**
|
||||
* Creates an Https configuration, with the given SSLContext.
|
||||
* @param context the SSLContext to use for this configurator
|
||||
* @throws NullPointerException if no SSLContext supplied
|
||||
*/
|
||||
public HttpsConfigurator (SSLContext context) {
|
||||
if (context == null) {
|
||||
throw new NullPointerException ("null SSLContext");
|
||||
}
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SSLContext for this HttpsConfigurator.
|
||||
* @return the SSLContext
|
||||
*/
|
||||
public SSLContext getSSLContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
//BEGIN_TIGER_EXCLUDE
|
||||
/**
|
||||
* Called by the HttpsServer to configure the parameters
|
||||
* for a https connection currently being established.
|
||||
* The implementation of configure() must call
|
||||
* {@link HttpsParameters#setSSLParameters(SSLParameters)}
|
||||
* in order to set the SSL parameters for the connection.
|
||||
* <p>
|
||||
* The default implementation of this method uses the
|
||||
* SSLParameters returned from <p>
|
||||
* {@code getSSLContext().getDefaultSSLParameters()}
|
||||
* <p>
|
||||
* configure() may be overridden in order to modify this behavior.
|
||||
* See, the example <a href="#example">above</a>.
|
||||
* @param params the HttpsParameters to be configured.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public void configure (HttpsParameters params) {
|
||||
params.setSSLParameters (getSSLContext().getDefaultSSLParameters());
|
||||
}
|
||||
//END_TIGER_EXCLUDE
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class encapsulates a HTTPS request received and a
|
||||
* response to be generated in one exchange and defines
|
||||
* the extensions to HttpExchange that are specific to the HTTPS protocol.
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public abstract class HttpsExchange extends HttpExchange {
|
||||
|
||||
protected HttpsExchange () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SSLSession for this exchange.
|
||||
* @return the SSLSession
|
||||
*/
|
||||
public abstract SSLSession getSSLSession ();
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
import java.net.InetSocketAddress;
|
||||
//BEGIN_TIGER_EXCLUDE
|
||||
import javax.net.ssl.SSLParameters;
|
||||
//END_TIGER_EXCLUDE
|
||||
|
||||
/**
|
||||
* Represents the set of parameters for each https
|
||||
* connection negotiated with clients. One of these
|
||||
* is created and passed to
|
||||
* {@link HttpsConfigurator#configure(HttpsParameters)}
|
||||
* for every incoming https connection,
|
||||
* in order to determine the parameters to use.
|
||||
* <p>
|
||||
* The underlying SSL parameters may be established either
|
||||
* via the set/get methods of this class, or else via
|
||||
* a {@link javax.net.ssl.SSLParameters} object. SSLParameters
|
||||
* is the preferred method, because in the future,
|
||||
* additional configuration capabilities may be added to that class, and
|
||||
* it is easier to determine the set of supported parameters and their
|
||||
* default values with SSLParameters. Also, if an SSLParameters object is
|
||||
* provided via
|
||||
* {@link #setSSLParameters(SSLParameters)} then those parameter settings
|
||||
* are used, and any settings made in this object are ignored.
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class HttpsParameters {
|
||||
|
||||
private String[] cipherSuites;
|
||||
private String[] protocols;
|
||||
private boolean wantClientAuth;
|
||||
private boolean needClientAuth;
|
||||
|
||||
protected HttpsParameters() {}
|
||||
|
||||
/**
|
||||
* Returns the HttpsConfigurator for this HttpsParameters.
|
||||
*/
|
||||
public abstract HttpsConfigurator getHttpsConfigurator();
|
||||
|
||||
/**
|
||||
* Returns the address of the remote client initiating the
|
||||
* connection.
|
||||
*/
|
||||
public abstract InetSocketAddress getClientAddress();
|
||||
|
||||
//BEGIN_TIGER_EXCLUDE
|
||||
/**
|
||||
* Sets the SSLParameters to use for this HttpsParameters.
|
||||
* The parameters must be supported by the SSLContext contained
|
||||
* by the HttpsConfigurator associated with this HttpsParameters.
|
||||
* If no parameters are set, then the default behavior is to use
|
||||
* the default parameters from the associated SSLContext.
|
||||
* @param params the SSLParameters to set. If <code>null</code>
|
||||
* then the existing parameters (if any) remain unchanged.
|
||||
* @throws IllegalArgumentException if any of the parameters are
|
||||
* invalid or unsupported.
|
||||
*/
|
||||
public abstract void setSSLParameters (SSLParameters params);
|
||||
//END_TIGER_EXCLUDE
|
||||
|
||||
/**
|
||||
* Returns a copy of the array of ciphersuites or null if none
|
||||
* have been set.
|
||||
*
|
||||
* @return a copy of the array of ciphersuites or null if none
|
||||
* have been set.
|
||||
*/
|
||||
public String[] getCipherSuites() {
|
||||
return cipherSuites != null ? cipherSuites.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array of ciphersuites.
|
||||
*
|
||||
* @param cipherSuites the array of ciphersuites (or null)
|
||||
*/
|
||||
public void setCipherSuites(String[] cipherSuites) {
|
||||
this.cipherSuites = cipherSuites != null ? cipherSuites.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the array of protocols or null if none
|
||||
* have been set.
|
||||
*
|
||||
* @return a copy of the array of protocols or null if none
|
||||
* have been set.
|
||||
*/
|
||||
public String[] getProtocols() {
|
||||
return protocols != null ? protocols.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array of protocols.
|
||||
*
|
||||
* @param protocols the array of protocols (or null)
|
||||
*/
|
||||
public void setProtocols(String[] protocols) {
|
||||
this.protocols = protocols != null ? protocols.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether client authentication should be requested.
|
||||
*
|
||||
* @return whether client authentication should be requested.
|
||||
*/
|
||||
public boolean getWantClientAuth() {
|
||||
return wantClientAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether client authentication should be requested. Calling
|
||||
* this method clears the <code>needClientAuth</code> flag.
|
||||
*
|
||||
* @param wantClientAuth whether client authentication should be requested
|
||||
*/
|
||||
public void setWantClientAuth(boolean wantClientAuth) {
|
||||
this.wantClientAuth = wantClientAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether client authentication should be required.
|
||||
*
|
||||
* @return whether client authentication should be required.
|
||||
*/
|
||||
public boolean getNeedClientAuth() {
|
||||
return needClientAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether client authentication should be required. Calling
|
||||
* this method clears the <code>wantClientAuth</code> flag.
|
||||
*
|
||||
* @param needClientAuth whether client authentication should be required
|
||||
*/
|
||||
public void setNeedClientAuth(boolean needClientAuth) {
|
||||
this.needClientAuth = needClientAuth;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.security.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import javax.net.ssl.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* This class is an extension of {@link HttpServer} which provides
|
||||
* support for HTTPS. <p>
|
||||
* A HttpsServer must have an associated {@link HttpsConfigurator} object
|
||||
* which is used to establish the SSL configuration for the SSL connections.
|
||||
* <p>
|
||||
* All other configuration is the same as for HttpServer.
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public abstract class HttpsServer extends HttpServer {
|
||||
|
||||
/**
|
||||
*/
|
||||
protected HttpsServer () {
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a HttpsServer instance which is initially not bound to any local address/port.
|
||||
* The HttpsServer is acquired from the currently installed {@link HttpServerProvider}
|
||||
* The server must be bound using {@link #bind(InetSocketAddress,int)} before it can be used.
|
||||
* The server must also have a HttpsConfigurator established with {@link #setHttpsConfigurator(HttpsConfigurator)}
|
||||
* @throws IOException
|
||||
*/
|
||||
public static HttpsServer create () throws IOException {
|
||||
return create (null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>HttpsServer</code> instance which will bind to the
|
||||
* specified {@link java.net.InetSocketAddress} (IP address and port number)
|
||||
*
|
||||
* A maximum backlog can also be specified. This is the maximum number of
|
||||
* queued incoming connections to allow on the listening socket.
|
||||
* Queued TCP connections exceeding this limit may be rejected by the TCP implementation.
|
||||
* The HttpsServer is acquired from the currently installed {@link HttpServerProvider}
|
||||
* The server must have a HttpsConfigurator established with {@link #setHttpsConfigurator(HttpsConfigurator)}
|
||||
*
|
||||
* @param addr the address to listen on, if <code>null</code> then bind() must be called
|
||||
* to set the address
|
||||
* @param backlog the socket backlog. If this value is less than or equal to zero,
|
||||
* then a system default value is used.
|
||||
* @throws BindException if the server cannot bind to the requested address,
|
||||
* or if the server is already bound.
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
public static HttpsServer create (
|
||||
InetSocketAddress addr, int backlog
|
||||
) throws IOException {
|
||||
HttpServerProvider provider = HttpServerProvider.provider();
|
||||
return provider.createHttpsServer (addr, backlog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this server's {@link HttpsConfigurator} object.
|
||||
* @param config the HttpsConfigurator to set
|
||||
* @throws NullPointerException if config is null.
|
||||
*/
|
||||
public abstract void setHttpsConfigurator (HttpsConfigurator config) ;
|
||||
|
||||
/**
|
||||
* Gets this server's {@link HttpsConfigurator} object, if it has been set.
|
||||
* @return the HttpsConfigurator for this server, or <code>null</code> if not set.
|
||||
*/
|
||||
public abstract HttpsConfigurator getHttpsConfigurator ();
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
Provides a simple high-level Http server API, which can be used to build
|
||||
embedded HTTP servers. Both "http" and "https" are supported. The API provides
|
||||
a partial implementation of RFC <a href="http://www.ietf.org/rfc/rfc2616.txt">2616</a> (HTTP 1.1)
|
||||
and RFC <a href="http://www.ietf.org/rfc/rfc2818.txt">2818</a> (HTTP over TLS).
|
||||
Any HTTP functionality not provided by this API can be implemented by application code
|
||||
using the API.
|
||||
<p>
|
||||
Programmers must implement the {@link com.sun.net.httpserver.HttpHandler} interface. This interface
|
||||
provides a callback which is invoked to handle incoming requests from clients.
|
||||
A HTTP request and its response is known as an exchange. HTTP exchanges are
|
||||
represented by the {@link com.sun.net.httpserver.HttpExchange} class.
|
||||
The {@link com.sun.net.httpserver.HttpServer} class is used to listen for incoming TCP connections
|
||||
and it dispatches requests on these connections to handlers which have been
|
||||
registered with the server.
|
||||
<p>
|
||||
A minimal Http server example is shown below:
|
||||
<blockquote><pre>
|
||||
class MyHandler implements HttpHandler {
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
InputStream is = t.getRequestBody();
|
||||
read(is); // .. read the request body
|
||||
String response = "This is the response";
|
||||
t.sendResponseHeaders(200, response.length());
|
||||
OutputStream os = t.getResponseBody();
|
||||
os.write(response.getBytes());
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
...
|
||||
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
|
||||
server.createContext("/applications/myapp", new MyHandler());
|
||||
server.setExecutor(null); // creates a default executor
|
||||
server.start();
|
||||
</pre></blockquote>
|
||||
<p>The example above creates a simple HttpServer which uses the calling
|
||||
application thread to invoke the handle() method for incoming http
|
||||
requests directed to port 8000, and to the path /applications/myapp/.
|
||||
<p>
|
||||
The {@link com.sun.net.httpserver.HttpExchange} class encapsulates everything an application needs to
|
||||
process incoming requests and to generate appropriate responses.
|
||||
<p>
|
||||
Registering a handler with a HttpServer creates a {@link com.sun.net.httpserver.HttpContext} object and
|
||||
{@link com.sun.net.httpserver.Filter}
|
||||
objects can be added to the returned context. Filters are used to perform automatic pre- and
|
||||
post-processing of exchanges before they are passed to the exchange handler.
|
||||
<p>
|
||||
For sensitive information, a {@link com.sun.net.httpserver.HttpsServer} can
|
||||
be used to process "https" requests secured by the SSL or TLS protocols.
|
||||
A HttpsServer must be provided with a
|
||||
{@link com.sun.net.httpserver.HttpsConfigurator} object, which contains an
|
||||
initialized {@link javax.net.ssl.SSLContext}.
|
||||
HttpsConfigurator can be used to configure the
|
||||
cipher suites and other SSL operating parameters.
|
||||
A simple example SSLContext could be created as follows:
|
||||
<blockquote><pre>
|
||||
char[] passphrase = "passphrase".toCharArray();
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
ks.load(new FileInputStream("testkeys"), passphrase);
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(ks, passphrase);
|
||||
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext ssl = SSLContext.getInstance("TLS");
|
||||
ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||
</pre></blockquote>
|
||||
<p>
|
||||
In the example above, a keystore file called "testkeys", created with the keytool utility
|
||||
is used as a certificate store for client and server certificates.
|
||||
The following code shows how the SSLContext is then used in a HttpsConfigurator
|
||||
and how the SSLContext and HttpsConfigurator are linked to the HttpsServer.
|
||||
<blockquote><pre>
|
||||
server.setHttpsConfigurator (new HttpsConfigurator(sslContext) {
|
||||
public void configure (HttpsParameters params) {
|
||||
|
||||
// get the remote address if needed
|
||||
InetSocketAddress remote = params.getClientAddress();
|
||||
|
||||
SSLContext c = getSSLContext();
|
||||
|
||||
// get the default parameters
|
||||
SSLParameters sslparams = c.getDefaultSSLParameters();
|
||||
if (remote.equals (...) ) {
|
||||
// modify the default set for client x
|
||||
}
|
||||
|
||||
params.setSSLParameters(sslparams);
|
||||
// statement above could throw IAE if any params invalid.
|
||||
// eg. if app has a UI and parameters supplied by a user.
|
||||
|
||||
}
|
||||
});
|
||||
</pre></blockquote>
|
||||
|
||||
@since 1.6
|
||||
*/
|
||||
package com.sun.net.httpserver;
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.net.httpserver.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
/**
|
||||
* Service provider class for HttpServer.
|
||||
* Sub-classes of HttpServerProvider provide an implementation of
|
||||
* {@link HttpServer} and associated classes. Applications do not normally use
|
||||
* this class. See {@link #provider()} for how providers are found and loaded.
|
||||
*/
|
||||
public abstract class HttpServerProvider {
|
||||
|
||||
/**
|
||||
* creates a HttpServer from this provider
|
||||
*
|
||||
* @param addr
|
||||
* the address to bind to. May be {@code null}
|
||||
*
|
||||
* @param backlog
|
||||
* the socket backlog. A value of {@code zero} means the systems default
|
||||
*/
|
||||
public abstract HttpServer createHttpServer(InetSocketAddress addr,
|
||||
int backlog)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* creates a HttpsServer from this provider
|
||||
*
|
||||
* @param addr
|
||||
* the address to bind to. May be {@code null}
|
||||
*
|
||||
* @param backlog
|
||||
* the socket backlog. A value of {@code zero} means the systems default
|
||||
*/
|
||||
public abstract HttpsServer createHttpsServer(InetSocketAddress addr,
|
||||
int backlog)
|
||||
throws IOException;
|
||||
|
||||
private static final Object lock = new Object();
|
||||
private static HttpServerProvider provider = null;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of this class.
|
||||
*
|
||||
* @throws SecurityException
|
||||
* If a security manager has been installed and it denies
|
||||
* {@link RuntimePermission}{@code ("httpServerProvider")}
|
||||
*/
|
||||
protected HttpServerProvider() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkPermission(new RuntimePermission("httpServerProvider"));
|
||||
}
|
||||
|
||||
private static boolean loadProviderFromProperty() {
|
||||
String cn = System.getProperty("com.sun.net.httpserver.HttpServerProvider");
|
||||
if (cn == null)
|
||||
return false;
|
||||
try {
|
||||
@SuppressWarnings("deprecation")
|
||||
Object o = Class.forName(cn, true,
|
||||
ClassLoader.getSystemClassLoader()).newInstance();
|
||||
provider = (HttpServerProvider)o;
|
||||
return true;
|
||||
} catch (ClassNotFoundException |
|
||||
IllegalAccessException |
|
||||
InstantiationException |
|
||||
SecurityException x) {
|
||||
throw new ServiceConfigurationError(null, x);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean loadProviderAsService() {
|
||||
Iterator<HttpServerProvider> i =
|
||||
ServiceLoader.load(HttpServerProvider.class,
|
||||
ClassLoader.getSystemClassLoader())
|
||||
.iterator();
|
||||
for (;;) {
|
||||
try {
|
||||
if (!i.hasNext())
|
||||
return false;
|
||||
provider = i.next();
|
||||
return true;
|
||||
} catch (ServiceConfigurationError sce) {
|
||||
if (sce.getCause() instanceof SecurityException) {
|
||||
// Ignore the security exception, try the next provider
|
||||
continue;
|
||||
}
|
||||
throw sce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the system wide default HttpServerProvider for this invocation of
|
||||
* the Java virtual machine.
|
||||
*
|
||||
* <p> The first invocation of this method locates the default provider
|
||||
* object as follows: </p>
|
||||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li><p> If the system property
|
||||
* {@code com.sun.net.httpserver.HttpServerProvider} is defined then it
|
||||
* is taken to be the fully-qualified name of a concrete provider class.
|
||||
* The class is loaded and instantiated; if this process fails then an
|
||||
* unspecified unchecked error or exception is thrown. </p></li>
|
||||
*
|
||||
* <li><p> If a provider class has been installed in a jar file that is
|
||||
* visible to the system class loader, and that jar file contains a
|
||||
* provider-configuration file named
|
||||
* {@code com.sun.net.httpserver.HttpServerProvider} in the resource
|
||||
* directory {@code META-INF/services}, then the first class name
|
||||
* specified in that file is taken. The class is loaded and
|
||||
* instantiated; if this process fails then an unspecified unchecked error
|
||||
* or exception is thrown. </p></li>
|
||||
*
|
||||
* <li><p> Finally, if no provider has been specified by any of the above
|
||||
* means then the system-default provider class is instantiated and the
|
||||
* result is returned. </p></li>
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* <p> Subsequent invocations of this method return the provider that was
|
||||
* returned by the first invocation. </p>
|
||||
*
|
||||
* @return The system-wide default HttpServerProvider
|
||||
*/
|
||||
public static HttpServerProvider provider () {
|
||||
synchronized (lock) {
|
||||
if (provider != null)
|
||||
return provider;
|
||||
return (HttpServerProvider)AccessController
|
||||
.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
if (loadProviderFromProperty())
|
||||
return provider;
|
||||
if (loadProviderAsService())
|
||||
return provider;
|
||||
provider = new sun.net.httpserver.DefaultHttpServerProvider();
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides a pluggable service provider interface, which allows the HTTP server
|
||||
* implementation to be replaced with other implementations.
|
||||
*/
|
||||
package com.sun.net.httpserver.spi;
|
40
src/jdk.httpserver/share/classes/module-info.java
Normal file
40
src/jdk.httpserver/share/classes/module-info.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the JDK-specific HTTP server API.
|
||||
*
|
||||
* @uses com.sun.net.httpserver.spi.HttpServerProvider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
module jdk.httpserver {
|
||||
|
||||
exports com.sun.net.httpserver;
|
||||
exports com.sun.net.httpserver.spi;
|
||||
|
||||
uses com.sun.net.httpserver.spi.HttpServerProvider;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import com.sun.net.httpserver.*;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import javax.security.auth.*;
|
||||
import javax.security.auth.callback.*;
|
||||
import javax.security.auth.login.*;
|
||||
|
||||
public class AuthFilter extends Filter {
|
||||
|
||||
private Authenticator authenticator;
|
||||
|
||||
public AuthFilter (Authenticator authenticator) {
|
||||
this.authenticator = authenticator;
|
||||
}
|
||||
|
||||
public String description () {
|
||||
return "Authentication filter";
|
||||
}
|
||||
|
||||
public void setAuthenticator (Authenticator a) {
|
||||
authenticator = a;
|
||||
}
|
||||
|
||||
public void consumeInput (HttpExchange t) throws IOException {
|
||||
InputStream i = t.getRequestBody();
|
||||
byte[] b = new byte [4096];
|
||||
while (i.read (b) != -1);
|
||||
i.close ();
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter's implementation, which is invoked by the server
|
||||
*/
|
||||
public void doFilter (HttpExchange t, Filter.Chain chain) throws IOException
|
||||
{
|
||||
if (authenticator != null) {
|
||||
Authenticator.Result r = authenticator.authenticate (t);
|
||||
if (r instanceof Authenticator.Success) {
|
||||
Authenticator.Success s = (Authenticator.Success)r;
|
||||
ExchangeImpl e = ExchangeImpl.get (t);
|
||||
e.setPrincipal (s.getPrincipal());
|
||||
chain.doFilter (t);
|
||||
} else if (r instanceof Authenticator.Retry) {
|
||||
Authenticator.Retry ry = (Authenticator.Retry)r;
|
||||
consumeInput (t);
|
||||
t.sendResponseHeaders (ry.getResponseCode(), -1);
|
||||
} else if (r instanceof Authenticator.Failure) {
|
||||
Authenticator.Failure f = (Authenticator.Failure)r;
|
||||
consumeInput (t);
|
||||
t.sendResponseHeaders (f.getResponseCode(), -1);
|
||||
}
|
||||
} else {
|
||||
chain.doFilter (t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
class ChunkedInputStream extends LeftOverInputStream {
|
||||
ChunkedInputStream (ExchangeImpl t, InputStream src) {
|
||||
super (t, src);
|
||||
}
|
||||
|
||||
private int remaining;
|
||||
|
||||
/* true when a chunk header needs to be read */
|
||||
|
||||
private boolean needToReadHeader = true;
|
||||
|
||||
final static char CR = '\r';
|
||||
final static char LF = '\n';
|
||||
/*
|
||||
* Maximum chunk header size of 2KB + 2 bytes for CRLF
|
||||
*/
|
||||
private final static int MAX_CHUNK_HEADER_SIZE = 2050;
|
||||
|
||||
private int numeric (char[] arr, int nchars) throws IOException {
|
||||
assert arr.length >= nchars;
|
||||
int len = 0;
|
||||
for (int i=0; i<nchars; i++) {
|
||||
char c = arr[i];
|
||||
int val=0;
|
||||
if (c>='0' && c <='9') {
|
||||
val = c - '0';
|
||||
} else if (c>='a' && c<= 'f') {
|
||||
val = c - 'a' + 10;
|
||||
} else if (c>='A' && c<= 'F') {
|
||||
val = c - 'A' + 10;
|
||||
} else {
|
||||
throw new IOException ("invalid chunk length");
|
||||
}
|
||||
len = len * 16 + val;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* read the chunk header line and return the chunk length
|
||||
* any chunk extensions are ignored
|
||||
*/
|
||||
private int readChunkHeader () throws IOException {
|
||||
boolean gotCR = false;
|
||||
int c;
|
||||
char[] len_arr = new char [16];
|
||||
int len_size = 0;
|
||||
boolean end_of_len = false;
|
||||
int read = 0;
|
||||
|
||||
while ((c=in.read())!= -1) {
|
||||
char ch = (char) c;
|
||||
read++;
|
||||
if ((len_size == len_arr.length -1) ||
|
||||
(read > MAX_CHUNK_HEADER_SIZE))
|
||||
{
|
||||
throw new IOException ("invalid chunk header");
|
||||
}
|
||||
if (gotCR) {
|
||||
if (ch == LF) {
|
||||
int l = numeric (len_arr, len_size);
|
||||
return l;
|
||||
} else {
|
||||
gotCR = false;
|
||||
}
|
||||
if (!end_of_len) {
|
||||
len_arr[len_size++] = ch;
|
||||
}
|
||||
} else {
|
||||
if (ch == CR) {
|
||||
gotCR = true;
|
||||
} else if (ch == ';') {
|
||||
end_of_len = true;
|
||||
} else if (!end_of_len) {
|
||||
len_arr[len_size++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IOException ("end of stream reading chunk header");
|
||||
}
|
||||
|
||||
protected int readImpl (byte[]b, int off, int len) throws IOException {
|
||||
if (eof) {
|
||||
return -1;
|
||||
}
|
||||
if (needToReadHeader) {
|
||||
remaining = readChunkHeader();
|
||||
if (remaining == 0) {
|
||||
eof = true;
|
||||
consumeCRLF();
|
||||
t.getServerImpl().requestCompleted (t.getConnection());
|
||||
return -1;
|
||||
}
|
||||
needToReadHeader = false;
|
||||
}
|
||||
if (len > remaining) {
|
||||
len = remaining;
|
||||
}
|
||||
int n = in.read(b, off, len);
|
||||
if (n > -1) {
|
||||
remaining -= n;
|
||||
}
|
||||
if (remaining == 0) {
|
||||
needToReadHeader = true;
|
||||
consumeCRLF();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private void consumeCRLF () throws IOException {
|
||||
char c;
|
||||
c = (char)in.read(); /* CR */
|
||||
if (c != CR) {
|
||||
throw new IOException ("invalid chunk end");
|
||||
}
|
||||
c = (char)in.read(); /* LF */
|
||||
if (c != LF) {
|
||||
throw new IOException ("invalid chunk end");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of bytes available to read in the current chunk
|
||||
* which may be less than the real amount, but we'll live with that
|
||||
* limitation for the moment. It only affects potential efficiency
|
||||
* rather than correctness.
|
||||
*/
|
||||
public int available () throws IOException {
|
||||
if (eof || closed) {
|
||||
return 0;
|
||||
}
|
||||
int n = in.available();
|
||||
return n > remaining? remaining: n;
|
||||
}
|
||||
|
||||
/* called after the stream is closed to see if bytes
|
||||
* have been read from the underlying channel
|
||||
* and buffered internally
|
||||
*/
|
||||
public boolean isDataBuffered () throws IOException {
|
||||
assert eof;
|
||||
return in.available() > 0;
|
||||
}
|
||||
|
||||
public boolean markSupported () {return false;}
|
||||
|
||||
public void mark (int l) {
|
||||
}
|
||||
|
||||
public void reset () throws IOException {
|
||||
throw new IOException ("mark/reset not supported");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* a class which allows the caller to write an arbitrary
|
||||
* number of bytes to an underlying stream.
|
||||
* normal close() does not close the underlying stream
|
||||
*
|
||||
* This class is buffered.
|
||||
*
|
||||
* Each chunk is written in one go as :-
|
||||
* abcd\r\nxxxxxxxxxxxxxx\r\n
|
||||
*
|
||||
* abcd is the chunk-size, and xxx is the chunk data
|
||||
* If the length is less than 4 chars (in size) then the buffer
|
||||
* is written with an offset.
|
||||
* Final chunk is:
|
||||
* 0\r\n\r\n
|
||||
*/
|
||||
|
||||
class ChunkedOutputStream extends FilterOutputStream
|
||||
{
|
||||
private boolean closed = false;
|
||||
/* max. amount of user data per chunk */
|
||||
final static int CHUNK_SIZE = 4096;
|
||||
/* allow 4 bytes for chunk-size plus 4 for CRLFs */
|
||||
final static int OFFSET = 6; /* initial <=4 bytes for len + CRLF */
|
||||
private int pos = OFFSET;
|
||||
private int count = 0;
|
||||
private byte[] buf = new byte [CHUNK_SIZE+OFFSET+2];
|
||||
ExchangeImpl t;
|
||||
|
||||
ChunkedOutputStream (ExchangeImpl t, OutputStream src) {
|
||||
super (src);
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public void write (int b) throws IOException {
|
||||
if (closed) {
|
||||
throw new StreamClosedException ();
|
||||
}
|
||||
buf [pos++] = (byte)b;
|
||||
count ++;
|
||||
if (count == CHUNK_SIZE) {
|
||||
writeChunk();
|
||||
}
|
||||
assert count < CHUNK_SIZE;
|
||||
}
|
||||
|
||||
public void write (byte[]b, int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new StreamClosedException ();
|
||||
}
|
||||
int remain = CHUNK_SIZE - count;
|
||||
if (len > remain) {
|
||||
System.arraycopy (b,off,buf,pos,remain);
|
||||
count = CHUNK_SIZE;
|
||||
writeChunk();
|
||||
len -= remain;
|
||||
off += remain;
|
||||
while (len >= CHUNK_SIZE) {
|
||||
System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE);
|
||||
len -= CHUNK_SIZE;
|
||||
off += CHUNK_SIZE;
|
||||
count = CHUNK_SIZE;
|
||||
writeChunk();
|
||||
}
|
||||
}
|
||||
if (len > 0) {
|
||||
System.arraycopy (b,off,buf,pos,len);
|
||||
count += len;
|
||||
pos += len;
|
||||
}
|
||||
if (count == CHUNK_SIZE) {
|
||||
writeChunk();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write out a chunk , and reset the pointers
|
||||
* chunk does not have to be CHUNK_SIZE bytes
|
||||
* count must == number of user bytes (<= CHUNK_SIZE)
|
||||
*/
|
||||
private void writeChunk () throws IOException {
|
||||
char[] c = Integer.toHexString (count).toCharArray();
|
||||
int clen = c.length;
|
||||
int startByte = 4 - clen;
|
||||
int i;
|
||||
for (i=0; i<clen; i++) {
|
||||
buf[startByte+i] = (byte)c[i];
|
||||
}
|
||||
buf[startByte + (i++)] = '\r';
|
||||
buf[startByte + (i++)] = '\n';
|
||||
buf[startByte + (i++) + count] = '\r';
|
||||
buf[startByte + (i++) + count] = '\n';
|
||||
out.write (buf, startByte, i+count);
|
||||
count = 0;
|
||||
pos = OFFSET;
|
||||
}
|
||||
|
||||
public void close () throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
flush();
|
||||
try {
|
||||
/* write an empty chunk */
|
||||
writeChunk();
|
||||
out.flush();
|
||||
LeftOverInputStream is = t.getOriginalInputStream();
|
||||
if (!is.isClosed()) {
|
||||
is.close();
|
||||
}
|
||||
/* some clients close the connection before empty chunk is sent */
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
WriteFinishedEvent e = new WriteFinishedEvent (t);
|
||||
t.getHttpContext().getServerImpl().addEvent (e);
|
||||
}
|
||||
|
||||
public void flush () throws IOException {
|
||||
if (closed) {
|
||||
throw new StreamClosedException ();
|
||||
}
|
||||
if (count > 0) {
|
||||
writeChunk();
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
}
|
109
src/jdk.httpserver/share/classes/sun/net/httpserver/Code.java
Normal file
109
src/jdk.httpserver/share/classes/sun/net/httpserver/Code.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
class Code {
|
||||
|
||||
public static final int HTTP_CONTINUE = 100;
|
||||
public static final int HTTP_OK = 200;
|
||||
public static final int HTTP_CREATED = 201;
|
||||
public static final int HTTP_ACCEPTED = 202;
|
||||
public static final int HTTP_NOT_AUTHORITATIVE = 203;
|
||||
public static final int HTTP_NO_CONTENT = 204;
|
||||
public static final int HTTP_RESET = 205;
|
||||
public static final int HTTP_PARTIAL = 206;
|
||||
public static final int HTTP_MULT_CHOICE = 300;
|
||||
public static final int HTTP_MOVED_PERM = 301;
|
||||
public static final int HTTP_MOVED_TEMP = 302;
|
||||
public static final int HTTP_SEE_OTHER = 303;
|
||||
public static final int HTTP_NOT_MODIFIED = 304;
|
||||
public static final int HTTP_USE_PROXY = 305;
|
||||
public static final int HTTP_BAD_REQUEST = 400;
|
||||
public static final int HTTP_UNAUTHORIZED = 401;
|
||||
public static final int HTTP_PAYMENT_REQUIRED = 402;
|
||||
public static final int HTTP_FORBIDDEN = 403;
|
||||
public static final int HTTP_NOT_FOUND = 404;
|
||||
public static final int HTTP_BAD_METHOD = 405;
|
||||
public static final int HTTP_NOT_ACCEPTABLE = 406;
|
||||
public static final int HTTP_PROXY_AUTH = 407;
|
||||
public static final int HTTP_CLIENT_TIMEOUT = 408;
|
||||
public static final int HTTP_CONFLICT = 409;
|
||||
public static final int HTTP_GONE = 410;
|
||||
public static final int HTTP_LENGTH_REQUIRED = 411;
|
||||
public static final int HTTP_PRECON_FAILED = 412;
|
||||
public static final int HTTP_ENTITY_TOO_LARGE = 413;
|
||||
public static final int HTTP_REQ_TOO_LONG = 414;
|
||||
public static final int HTTP_UNSUPPORTED_TYPE = 415;
|
||||
public static final int HTTP_INTERNAL_ERROR = 500;
|
||||
public static final int HTTP_NOT_IMPLEMENTED = 501;
|
||||
public static final int HTTP_BAD_GATEWAY = 502;
|
||||
public static final int HTTP_UNAVAILABLE = 503;
|
||||
public static final int HTTP_GATEWAY_TIMEOUT = 504;
|
||||
public static final int HTTP_VERSION = 505;
|
||||
|
||||
static String msg (int code) {
|
||||
|
||||
switch (code) {
|
||||
case HTTP_OK: return " OK";
|
||||
case HTTP_CONTINUE: return " Continue";
|
||||
case HTTP_CREATED: return " Created";
|
||||
case HTTP_ACCEPTED: return " Accepted";
|
||||
case HTTP_NOT_AUTHORITATIVE: return " Non-Authoritative Information";
|
||||
case HTTP_NO_CONTENT: return " No Content";
|
||||
case HTTP_RESET: return " Reset Content";
|
||||
case HTTP_PARTIAL: return " Partial Content";
|
||||
case HTTP_MULT_CHOICE: return " Multiple Choices";
|
||||
case HTTP_MOVED_PERM: return " Moved Permanently";
|
||||
case HTTP_MOVED_TEMP: return " Temporary Redirect";
|
||||
case HTTP_SEE_OTHER: return " See Other";
|
||||
case HTTP_NOT_MODIFIED: return " Not Modified";
|
||||
case HTTP_USE_PROXY: return " Use Proxy";
|
||||
case HTTP_BAD_REQUEST: return " Bad Request";
|
||||
case HTTP_UNAUTHORIZED: return " Unauthorized" ;
|
||||
case HTTP_PAYMENT_REQUIRED: return " Payment Required";
|
||||
case HTTP_FORBIDDEN: return " Forbidden";
|
||||
case HTTP_NOT_FOUND: return " Not Found";
|
||||
case HTTP_BAD_METHOD: return " Method Not Allowed";
|
||||
case HTTP_NOT_ACCEPTABLE: return " Not Acceptable";
|
||||
case HTTP_PROXY_AUTH: return " Proxy Authentication Required";
|
||||
case HTTP_CLIENT_TIMEOUT: return " Request Time-Out";
|
||||
case HTTP_CONFLICT: return " Conflict";
|
||||
case HTTP_GONE: return " Gone";
|
||||
case HTTP_LENGTH_REQUIRED: return " Length Required";
|
||||
case HTTP_PRECON_FAILED: return " Precondition Failed";
|
||||
case HTTP_ENTITY_TOO_LARGE: return " Request Entity Too Large";
|
||||
case HTTP_REQ_TOO_LONG: return " Request-URI Too Large";
|
||||
case HTTP_UNSUPPORTED_TYPE: return " Unsupported Media Type";
|
||||
case HTTP_INTERNAL_ERROR: return " Internal Server Error";
|
||||
case HTTP_NOT_IMPLEMENTED: return " Not Implemented";
|
||||
case HTTP_BAD_GATEWAY: return " Bad Gateway";
|
||||
case HTTP_UNAVAILABLE: return " Service Unavailable";
|
||||
case HTTP_GATEWAY_TIMEOUT: return " Gateway Timeout";
|
||||
case HTTP_VERSION: return " HTTP Version Not Supported";
|
||||
default: return " ";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.util.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
class ContextList {
|
||||
|
||||
final static int MAX_CONTEXTS = 50;
|
||||
|
||||
LinkedList<HttpContextImpl> list = new LinkedList<HttpContextImpl>();
|
||||
|
||||
public synchronized void add (HttpContextImpl ctx) {
|
||||
assert ctx.getPath() != null;
|
||||
list.add (ctx);
|
||||
}
|
||||
|
||||
public synchronized int size () {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/* initially contexts are located only by protocol:path.
|
||||
* Context with longest prefix matches (currently case-sensitive)
|
||||
*/
|
||||
synchronized HttpContextImpl findContext (String protocol, String path) {
|
||||
return findContext (protocol, path, false);
|
||||
}
|
||||
|
||||
synchronized HttpContextImpl findContext (String protocol, String path, boolean exact) {
|
||||
protocol = protocol.toLowerCase();
|
||||
String longest = "";
|
||||
HttpContextImpl lc = null;
|
||||
for (HttpContextImpl ctx: list) {
|
||||
if (!ctx.getProtocol().equals(protocol)) {
|
||||
continue;
|
||||
}
|
||||
String cpath = ctx.getPath();
|
||||
if (exact && !cpath.equals (path)) {
|
||||
continue;
|
||||
} else if (!exact && !path.startsWith(cpath)) {
|
||||
continue;
|
||||
}
|
||||
if (cpath.length() > longest.length()) {
|
||||
longest = cpath;
|
||||
lc = ctx;
|
||||
}
|
||||
}
|
||||
return lc;
|
||||
}
|
||||
|
||||
public synchronized void remove (String protocol, String path)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
HttpContextImpl ctx = findContext (protocol, path, true);
|
||||
if (ctx == null) {
|
||||
throw new IllegalArgumentException ("cannot remove element from list");
|
||||
}
|
||||
list.remove (ctx);
|
||||
}
|
||||
|
||||
public synchronized void remove (HttpContextImpl context)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
for (HttpContextImpl ctx: list) {
|
||||
if (ctx.equals (context)) {
|
||||
list.remove (ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException ("no such context in list");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
public class DefaultHttpServerProvider extends HttpServerProvider {
|
||||
public HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException {
|
||||
return new HttpServerImpl (addr, backlog);
|
||||
}
|
||||
|
||||
public HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException {
|
||||
return new HttpsServerImpl (addr, backlog);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
class Event {
|
||||
|
||||
ExchangeImpl exchange;
|
||||
|
||||
protected Event (ExchangeImpl t) {
|
||||
this.exchange = t;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.util.*;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.text.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
class ExchangeImpl {
|
||||
|
||||
Headers reqHdrs, rspHdrs;
|
||||
Request req;
|
||||
String method;
|
||||
boolean writefinished;
|
||||
URI uri;
|
||||
HttpConnection connection;
|
||||
long reqContentLen;
|
||||
long rspContentLen;
|
||||
/* raw streams which access the socket directly */
|
||||
InputStream ris;
|
||||
OutputStream ros;
|
||||
Thread thread;
|
||||
/* close the underlying connection when this exchange finished */
|
||||
boolean close;
|
||||
boolean closed;
|
||||
boolean http10 = false;
|
||||
|
||||
/* for formatting the Date: header */
|
||||
private static final String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
|
||||
private static final TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
|
||||
private static final ThreadLocal<DateFormat> dateFormat =
|
||||
new ThreadLocal<DateFormat>() {
|
||||
@Override protected DateFormat initialValue() {
|
||||
DateFormat df = new SimpleDateFormat(pattern, Locale.US);
|
||||
df.setTimeZone(gmtTZ);
|
||||
return df;
|
||||
}
|
||||
};
|
||||
|
||||
private static final String HEAD = "HEAD";
|
||||
|
||||
/* streams which take care of the HTTP protocol framing
|
||||
* and are passed up to higher layers
|
||||
*/
|
||||
InputStream uis;
|
||||
OutputStream uos;
|
||||
LeftOverInputStream uis_orig; // uis may have be a user supplied wrapper
|
||||
PlaceholderOutputStream uos_orig;
|
||||
|
||||
boolean sentHeaders; /* true after response headers sent */
|
||||
Map<String,Object> attributes;
|
||||
int rcode = -1;
|
||||
HttpPrincipal principal;
|
||||
ServerImpl server;
|
||||
|
||||
ExchangeImpl (
|
||||
String m, URI u, Request req, long len, HttpConnection connection
|
||||
) throws IOException {
|
||||
this.req = req;
|
||||
this.reqHdrs = req.headers();
|
||||
this.rspHdrs = new Headers();
|
||||
this.method = m;
|
||||
this.uri = u;
|
||||
this.connection = connection;
|
||||
this.reqContentLen = len;
|
||||
/* ros only used for headers, body written directly to stream */
|
||||
this.ros = req.outputStream();
|
||||
this.ris = req.inputStream();
|
||||
server = getServerImpl();
|
||||
server.startExchange();
|
||||
}
|
||||
|
||||
public Headers getRequestHeaders () {
|
||||
return new UnmodifiableHeaders (reqHdrs);
|
||||
}
|
||||
|
||||
public Headers getResponseHeaders () {
|
||||
return rspHdrs;
|
||||
}
|
||||
|
||||
public URI getRequestURI () {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public String getRequestMethod (){
|
||||
return method;
|
||||
}
|
||||
|
||||
public HttpContextImpl getHttpContext (){
|
||||
return connection.getHttpContext();
|
||||
}
|
||||
|
||||
private boolean isHeadRequest() {
|
||||
return HEAD.equals(getRequestMethod());
|
||||
}
|
||||
|
||||
public void close () {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
|
||||
/* close the underlying connection if,
|
||||
* a) the streams not set up yet, no response can be sent, or
|
||||
* b) if the wrapper output stream is not set up, or
|
||||
* c) if the close of the input/outpu stream fails
|
||||
*/
|
||||
try {
|
||||
if (uis_orig == null || uos == null) {
|
||||
connection.close();
|
||||
return;
|
||||
}
|
||||
if (!uos_orig.isWrapped()) {
|
||||
connection.close();
|
||||
return;
|
||||
}
|
||||
if (!uis_orig.isClosed()) {
|
||||
uis_orig.close();
|
||||
}
|
||||
uos.close();
|
||||
} catch (IOException e) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream getRequestBody () {
|
||||
if (uis != null) {
|
||||
return uis;
|
||||
}
|
||||
if (reqContentLen == -1L) {
|
||||
uis_orig = new ChunkedInputStream (this, ris);
|
||||
uis = uis_orig;
|
||||
} else {
|
||||
uis_orig = new FixedLengthInputStream (this, ris, reqContentLen);
|
||||
uis = uis_orig;
|
||||
}
|
||||
return uis;
|
||||
}
|
||||
|
||||
LeftOverInputStream getOriginalInputStream () {
|
||||
return uis_orig;
|
||||
}
|
||||
|
||||
public int getResponseCode () {
|
||||
return rcode;
|
||||
}
|
||||
|
||||
public OutputStream getResponseBody () {
|
||||
/* TODO. Change spec to remove restriction below. Filters
|
||||
* cannot work with this restriction
|
||||
*
|
||||
* if (!sentHeaders) {
|
||||
* throw new IllegalStateException ("headers not sent");
|
||||
* }
|
||||
*/
|
||||
if (uos == null) {
|
||||
uos_orig = new PlaceholderOutputStream (null);
|
||||
uos = uos_orig;
|
||||
}
|
||||
return uos;
|
||||
}
|
||||
|
||||
|
||||
/* returns the place holder stream, which is the stream
|
||||
* returned from the 1st call to getResponseBody()
|
||||
* The "real" ouputstream is then placed inside this
|
||||
*/
|
||||
PlaceholderOutputStream getPlaceholderResponseBody () {
|
||||
getResponseBody();
|
||||
return uos_orig;
|
||||
}
|
||||
|
||||
public void sendResponseHeaders (int rCode, long contentLen)
|
||||
throws IOException
|
||||
{
|
||||
if (sentHeaders) {
|
||||
throw new IOException ("headers already sent");
|
||||
}
|
||||
this.rcode = rCode;
|
||||
String statusLine = "HTTP/1.1 "+rCode+Code.msg(rCode)+"\r\n";
|
||||
OutputStream tmpout = new BufferedOutputStream (ros);
|
||||
PlaceholderOutputStream o = getPlaceholderResponseBody();
|
||||
tmpout.write (bytes(statusLine, 0), 0, statusLine.length());
|
||||
boolean noContentToSend = false; // assume there is content
|
||||
rspHdrs.set ("Date", dateFormat.get().format (new Date()));
|
||||
|
||||
/* check for response type that is not allowed to send a body */
|
||||
|
||||
if ((rCode>=100 && rCode <200) /* informational */
|
||||
||(rCode == 204) /* no content */
|
||||
||(rCode == 304)) /* not modified */
|
||||
{
|
||||
if (contentLen != -1) {
|
||||
Logger logger = server.getLogger();
|
||||
String msg = "sendResponseHeaders: rCode = "+ rCode
|
||||
+ ": forcing contentLen = -1";
|
||||
logger.log (Level.WARNING, msg);
|
||||
}
|
||||
contentLen = -1;
|
||||
}
|
||||
|
||||
if (isHeadRequest()) {
|
||||
/* HEAD requests should not set a content length by passing it
|
||||
* through this API, but should instead manually set the required
|
||||
* headers.*/
|
||||
if (contentLen >= 0) {
|
||||
final Logger logger = server.getLogger();
|
||||
String msg =
|
||||
"sendResponseHeaders: being invoked with a content length for a HEAD request";
|
||||
logger.log (Level.WARNING, msg);
|
||||
}
|
||||
noContentToSend = true;
|
||||
contentLen = 0;
|
||||
} else { /* not a HEAD request */
|
||||
if (contentLen == 0) {
|
||||
if (http10) {
|
||||
o.setWrappedStream (new UndefLengthOutputStream (this, ros));
|
||||
close = true;
|
||||
} else {
|
||||
rspHdrs.set ("Transfer-encoding", "chunked");
|
||||
o.setWrappedStream (new ChunkedOutputStream (this, ros));
|
||||
}
|
||||
} else {
|
||||
if (contentLen == -1) {
|
||||
noContentToSend = true;
|
||||
contentLen = 0;
|
||||
}
|
||||
rspHdrs.set("Content-length", Long.toString(contentLen));
|
||||
o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen));
|
||||
}
|
||||
}
|
||||
write (rspHdrs, tmpout);
|
||||
this.rspContentLen = contentLen;
|
||||
tmpout.flush() ;
|
||||
tmpout = null;
|
||||
sentHeaders = true;
|
||||
if (noContentToSend) {
|
||||
WriteFinishedEvent e = new WriteFinishedEvent (this);
|
||||
server.addEvent (e);
|
||||
closed = true;
|
||||
}
|
||||
server.logReply (rCode, req.requestLine(), null);
|
||||
}
|
||||
|
||||
void write (Headers map, OutputStream os) throws IOException {
|
||||
Set<Map.Entry<String,List<String>>> entries = map.entrySet();
|
||||
for (Map.Entry<String,List<String>> entry : entries) {
|
||||
String key = entry.getKey();
|
||||
byte[] buf;
|
||||
List<String> values = entry.getValue();
|
||||
for (String val : values) {
|
||||
int i = key.length();
|
||||
buf = bytes (key, 2);
|
||||
buf[i++] = ':';
|
||||
buf[i++] = ' ';
|
||||
os.write (buf, 0, i);
|
||||
buf = bytes (val, 2);
|
||||
i = val.length();
|
||||
buf[i++] = '\r';
|
||||
buf[i++] = '\n';
|
||||
os.write (buf, 0, i);
|
||||
}
|
||||
}
|
||||
os.write ('\r');
|
||||
os.write ('\n');
|
||||
}
|
||||
|
||||
private byte[] rspbuf = new byte [128]; // used by bytes()
|
||||
|
||||
/**
|
||||
* convert string to byte[], using rspbuf
|
||||
* Make sure that at least "extra" bytes are free at end
|
||||
* of rspbuf. Reallocate rspbuf if not big enough.
|
||||
* caller must check return value to see if rspbuf moved
|
||||
*/
|
||||
private byte[] bytes (String s, int extra) {
|
||||
int slen = s.length();
|
||||
if (slen+extra > rspbuf.length) {
|
||||
int diff = slen + extra - rspbuf.length;
|
||||
rspbuf = new byte [2* (rspbuf.length + diff)];
|
||||
}
|
||||
char c[] = s.toCharArray();
|
||||
for (int i=0; i<c.length; i++) {
|
||||
rspbuf[i] = (byte)c[i];
|
||||
}
|
||||
return rspbuf;
|
||||
}
|
||||
|
||||
public InetSocketAddress getRemoteAddress (){
|
||||
Socket s = connection.getChannel().socket();
|
||||
InetAddress ia = s.getInetAddress();
|
||||
int port = s.getPort();
|
||||
return new InetSocketAddress (ia, port);
|
||||
}
|
||||
|
||||
public InetSocketAddress getLocalAddress (){
|
||||
Socket s = connection.getChannel().socket();
|
||||
InetAddress ia = s.getLocalAddress();
|
||||
int port = s.getLocalPort();
|
||||
return new InetSocketAddress (ia, port);
|
||||
}
|
||||
|
||||
public String getProtocol (){
|
||||
String reqline = req.requestLine();
|
||||
int index = reqline.lastIndexOf (' ');
|
||||
return reqline.substring (index+1);
|
||||
}
|
||||
|
||||
public SSLSession getSSLSession () {
|
||||
SSLEngine e = connection.getSSLEngine();
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
return e.getSession();
|
||||
}
|
||||
|
||||
public Object getAttribute (String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException ("null name parameter");
|
||||
}
|
||||
if (attributes == null) {
|
||||
attributes = getHttpContext().getAttributes();
|
||||
}
|
||||
return attributes.get (name);
|
||||
}
|
||||
|
||||
public void setAttribute (String name, Object value) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException ("null name parameter");
|
||||
}
|
||||
if (attributes == null) {
|
||||
attributes = getHttpContext().getAttributes();
|
||||
}
|
||||
attributes.put (name, value);
|
||||
}
|
||||
|
||||
public void setStreams (InputStream i, OutputStream o) {
|
||||
assert uis != null;
|
||||
if (i != null) {
|
||||
uis = i;
|
||||
}
|
||||
if (o != null) {
|
||||
uos = o;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PP
|
||||
*/
|
||||
HttpConnection getConnection () {
|
||||
return connection;
|
||||
}
|
||||
|
||||
ServerImpl getServerImpl () {
|
||||
return getHttpContext().getServerImpl();
|
||||
}
|
||||
|
||||
public HttpPrincipal getPrincipal () {
|
||||
return principal;
|
||||
}
|
||||
|
||||
void setPrincipal (HttpPrincipal principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
static ExchangeImpl get (HttpExchange t) {
|
||||
if (t instanceof HttpExchangeImpl) {
|
||||
return ((HttpExchangeImpl)t).getExchangeImpl();
|
||||
} else {
|
||||
assert t instanceof HttpsExchangeImpl;
|
||||
return ((HttpsExchangeImpl)t).getExchangeImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An OutputStream which wraps another stream
|
||||
* which is supplied either at creation time, or sometime later.
|
||||
* If a caller/user tries to write to this stream before
|
||||
* the wrapped stream has been provided, then an IOException will
|
||||
* be thrown.
|
||||
*/
|
||||
class PlaceholderOutputStream extends java.io.OutputStream {
|
||||
|
||||
OutputStream wrapped;
|
||||
|
||||
PlaceholderOutputStream (OutputStream os) {
|
||||
wrapped = os;
|
||||
}
|
||||
|
||||
void setWrappedStream (OutputStream os) {
|
||||
wrapped = os;
|
||||
}
|
||||
|
||||
boolean isWrapped () {
|
||||
return wrapped != null;
|
||||
}
|
||||
|
||||
private void checkWrap () throws IOException {
|
||||
if (wrapped == null) {
|
||||
throw new IOException ("response headers not sent yet");
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
checkWrap();
|
||||
wrapped.write (b);
|
||||
}
|
||||
|
||||
public void write(byte b[]) throws IOException {
|
||||
checkWrap();
|
||||
wrapped.write (b);
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
checkWrap();
|
||||
wrapped.write (b, off, len);
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
checkWrap();
|
||||
wrapped.flush();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
checkWrap();
|
||||
wrapped.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* a class which allows the caller to read up to a defined
|
||||
* number of bytes off an underlying stream
|
||||
* close() does not close the underlying stream
|
||||
*/
|
||||
|
||||
class FixedLengthInputStream extends LeftOverInputStream {
|
||||
private long remaining;
|
||||
|
||||
FixedLengthInputStream (ExchangeImpl t, InputStream src, long len) {
|
||||
super (t, src);
|
||||
this.remaining = len;
|
||||
}
|
||||
|
||||
protected int readImpl (byte[]b, int off, int len) throws IOException {
|
||||
|
||||
eof = (remaining == 0L);
|
||||
if (eof) {
|
||||
return -1;
|
||||
}
|
||||
if (len > remaining) {
|
||||
len = (int)remaining;
|
||||
}
|
||||
int n = in.read(b, off, len);
|
||||
if (n > -1) {
|
||||
remaining -= n;
|
||||
if (remaining == 0) {
|
||||
t.getServerImpl().requestCompleted (t.getConnection());
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public int available () throws IOException {
|
||||
if (eof) {
|
||||
return 0;
|
||||
}
|
||||
int n = in.available();
|
||||
return n < remaining? n: (int)remaining;
|
||||
}
|
||||
|
||||
public boolean markSupported () {return false;}
|
||||
|
||||
public void mark (int l) {
|
||||
}
|
||||
|
||||
public void reset () throws IOException {
|
||||
throw new IOException ("mark/reset not supported");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* a class which allows the caller to write up to a defined
|
||||
* number of bytes to an underlying stream. The caller *must*
|
||||
* write the pre-defined number or else an exception will be thrown
|
||||
* and the whole request aborted.
|
||||
* normal close() does not close the underlying stream
|
||||
*/
|
||||
|
||||
class FixedLengthOutputStream extends FilterOutputStream
|
||||
{
|
||||
private long remaining;
|
||||
private boolean eof = false;
|
||||
private boolean closed = false;
|
||||
ExchangeImpl t;
|
||||
|
||||
FixedLengthOutputStream (ExchangeImpl t, OutputStream src, long len) {
|
||||
super (src);
|
||||
this.t = t;
|
||||
this.remaining = len;
|
||||
}
|
||||
|
||||
public void write (int b) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("stream closed");
|
||||
}
|
||||
eof = (remaining == 0);
|
||||
if (eof) {
|
||||
throw new StreamClosedException();
|
||||
}
|
||||
out.write(b);
|
||||
remaining --;
|
||||
}
|
||||
|
||||
public void write (byte[]b, int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("stream closed");
|
||||
}
|
||||
eof = (remaining == 0);
|
||||
if (eof) {
|
||||
throw new StreamClosedException();
|
||||
}
|
||||
if (len > remaining) {
|
||||
// stream is still open, caller can retry
|
||||
throw new IOException ("too many bytes to write to stream");
|
||||
}
|
||||
out.write(b, off, len);
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
public void close () throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
if (remaining > 0) {
|
||||
t.close();
|
||||
throw new IOException ("insufficient bytes written to stream");
|
||||
}
|
||||
flush();
|
||||
eof = true;
|
||||
LeftOverInputStream is = t.getOriginalInputStream();
|
||||
if (!is.isClosed()) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
WriteFinishedEvent e = new WriteFinishedEvent (t);
|
||||
t.getHttpContext().getServerImpl().addEvent (e);
|
||||
}
|
||||
|
||||
// flush is a pass-through
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.nio.channels.*;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* encapsulates all the connection specific state for a HTTP/S connection
|
||||
* one of these is hung from the selector attachment and is used to locate
|
||||
* everything from that.
|
||||
*/
|
||||
class HttpConnection {
|
||||
|
||||
HttpContextImpl context;
|
||||
SSLEngine engine;
|
||||
SSLContext sslContext;
|
||||
SSLStreams sslStreams;
|
||||
|
||||
/* high level streams returned to application */
|
||||
InputStream i;
|
||||
|
||||
/* low level stream that sits directly over channel */
|
||||
InputStream raw;
|
||||
OutputStream rawout;
|
||||
|
||||
SocketChannel chan;
|
||||
SelectionKey selectionKey;
|
||||
String protocol;
|
||||
long time;
|
||||
volatile long creationTime; // time this connection was created
|
||||
volatile long rspStartedTime; // time we started writing the response
|
||||
int remaining;
|
||||
boolean closed = false;
|
||||
Logger logger;
|
||||
|
||||
public enum State {IDLE, REQUEST, RESPONSE};
|
||||
volatile State state;
|
||||
|
||||
public String toString() {
|
||||
String s = null;
|
||||
if (chan != null) {
|
||||
s = chan.toString();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
HttpConnection () {
|
||||
}
|
||||
|
||||
void setChannel (SocketChannel c) {
|
||||
chan = c;
|
||||
}
|
||||
|
||||
void setContext (HttpContextImpl ctx) {
|
||||
context = ctx;
|
||||
}
|
||||
|
||||
State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
void setState (State s) {
|
||||
state = s;
|
||||
}
|
||||
|
||||
void setParameters (
|
||||
InputStream in, OutputStream rawout, SocketChannel chan,
|
||||
SSLEngine engine, SSLStreams sslStreams, SSLContext sslContext, String protocol,
|
||||
HttpContextImpl context, InputStream raw
|
||||
)
|
||||
{
|
||||
this.context = context;
|
||||
this.i = in;
|
||||
this.rawout = rawout;
|
||||
this.raw = raw;
|
||||
this.protocol = protocol;
|
||||
this.engine = engine;
|
||||
this.chan = chan;
|
||||
this.sslContext = sslContext;
|
||||
this.sslStreams = sslStreams;
|
||||
this.logger = context.getLogger();
|
||||
}
|
||||
|
||||
SocketChannel getChannel () {
|
||||
return chan;
|
||||
}
|
||||
|
||||
synchronized void close () {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
if (logger != null && chan != null) {
|
||||
logger.log (Level.TRACE, "Closing connection: " + chan.toString());
|
||||
}
|
||||
|
||||
if (!chan.isOpen()) {
|
||||
ServerImpl.dprint ("Channel already closed");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
/* need to ensure temporary selectors are closed */
|
||||
if (raw != null) {
|
||||
raw.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ServerImpl.dprint (e);
|
||||
}
|
||||
try {
|
||||
if (rawout != null) {
|
||||
rawout.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ServerImpl.dprint (e);
|
||||
}
|
||||
try {
|
||||
if (sslStreams != null) {
|
||||
sslStreams.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ServerImpl.dprint (e);
|
||||
}
|
||||
try {
|
||||
chan.close();
|
||||
} catch (IOException e) {
|
||||
ServerImpl.dprint (e);
|
||||
}
|
||||
}
|
||||
|
||||
/* remaining is the number of bytes left on the lowest level inputstream
|
||||
* after the exchange is finished
|
||||
*/
|
||||
void setRemaining (int r) {
|
||||
remaining = r;
|
||||
}
|
||||
|
||||
int getRemaining () {
|
||||
return remaining;
|
||||
}
|
||||
|
||||
SelectionKey getSelectionKey () {
|
||||
return selectionKey;
|
||||
}
|
||||
|
||||
InputStream getInputStream () {
|
||||
return i;
|
||||
}
|
||||
|
||||
OutputStream getRawOutputStream () {
|
||||
return rawout;
|
||||
}
|
||||
|
||||
String getProtocol () {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
SSLEngine getSSLEngine () {
|
||||
return engine;
|
||||
}
|
||||
|
||||
SSLContext getSSLContext () {
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
HttpContextImpl getHttpContext () {
|
||||
return context;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.lang.System.Logger;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* HttpContext represents a mapping between a protocol (http or https) together with a root URI path
|
||||
* to a {@link HttpHandler} which is invoked to handle requests destined
|
||||
* for the protocol/path on the associated HttpServer.
|
||||
* <p>
|
||||
* HttpContext instances are created by {@link HttpServer#createContext(String,String,HttpHandler,Object)}
|
||||
* <p>
|
||||
*/
|
||||
class HttpContextImpl extends HttpContext {
|
||||
|
||||
private String path;
|
||||
private String protocol;
|
||||
private HttpHandler handler;
|
||||
private Map<String,Object> attributes = new HashMap<String,Object>();
|
||||
private ServerImpl server;
|
||||
/* system filters, not visible to applications */
|
||||
private LinkedList<Filter> sfilters = new LinkedList<Filter>();
|
||||
/* user filters, set by applications */
|
||||
private LinkedList<Filter> ufilters = new LinkedList<Filter>();
|
||||
private Authenticator authenticator;
|
||||
private AuthFilter authfilter;
|
||||
|
||||
/**
|
||||
* constructor is package private.
|
||||
*/
|
||||
HttpContextImpl (String protocol, String path, HttpHandler cb, ServerImpl server) {
|
||||
if (path == null || protocol == null || path.length() < 1 || path.charAt(0) != '/') {
|
||||
throw new IllegalArgumentException ("Illegal value for path or protocol");
|
||||
}
|
||||
this.protocol = protocol.toLowerCase();
|
||||
this.path = path;
|
||||
if (!this.protocol.equals ("http") && !this.protocol.equals ("https")) {
|
||||
throw new IllegalArgumentException ("Illegal value for protocol");
|
||||
}
|
||||
this.handler = cb;
|
||||
this.server = server;
|
||||
authfilter = new AuthFilter(null);
|
||||
sfilters.add (authfilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the handler for this context
|
||||
* @return the HttpHandler for this context
|
||||
*/
|
||||
public HttpHandler getHandler () {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void setHandler (HttpHandler h) {
|
||||
if (h == null) {
|
||||
throw new NullPointerException ("Null handler parameter");
|
||||
}
|
||||
if (handler != null) {
|
||||
throw new IllegalArgumentException ("handler already set");
|
||||
}
|
||||
handler = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the path this context was created with
|
||||
* @return this context's path
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the server this context was created with
|
||||
* @return this context's server
|
||||
*/
|
||||
public HttpServer getServer () {
|
||||
return server.getWrapper();
|
||||
}
|
||||
|
||||
ServerImpl getServerImpl () {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the protocol this context was created with
|
||||
* @return this context's path
|
||||
*/
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a mutable Map, which can be used to pass
|
||||
* configuration and other data to Filter modules
|
||||
* and to the context's exchange handler.
|
||||
* <p>
|
||||
* Every attribute stored in this Map will be visible to
|
||||
* every HttpExchange processed by this context
|
||||
*/
|
||||
public Map<String,Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public List<Filter> getFilters () {
|
||||
return ufilters;
|
||||
}
|
||||
|
||||
List<Filter> getSystemFilters () {
|
||||
return sfilters;
|
||||
}
|
||||
|
||||
public Authenticator setAuthenticator (Authenticator auth) {
|
||||
Authenticator old = authenticator;
|
||||
authenticator = auth;
|
||||
authfilter.setAuthenticator (auth);
|
||||
return old;
|
||||
}
|
||||
|
||||
public Authenticator getAuthenticator () {
|
||||
return authenticator;
|
||||
}
|
||||
Logger getLogger () {
|
||||
return server.getLogger();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
/**
|
||||
* A Http error
|
||||
*/
|
||||
class HttpError extends RuntimeException {
|
||||
private static final long serialVersionUID = 8769596371344178179L;
|
||||
|
||||
public HttpError (String msg) {
|
||||
super (msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.util.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
class HttpExchangeImpl extends HttpExchange {
|
||||
|
||||
ExchangeImpl impl;
|
||||
|
||||
HttpExchangeImpl (ExchangeImpl impl) {
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
public Headers getRequestHeaders () {
|
||||
return impl.getRequestHeaders();
|
||||
}
|
||||
|
||||
public Headers getResponseHeaders () {
|
||||
return impl.getResponseHeaders();
|
||||
}
|
||||
|
||||
public URI getRequestURI () {
|
||||
return impl.getRequestURI();
|
||||
}
|
||||
|
||||
public String getRequestMethod (){
|
||||
return impl.getRequestMethod();
|
||||
}
|
||||
|
||||
public HttpContextImpl getHttpContext (){
|
||||
return impl.getHttpContext();
|
||||
}
|
||||
|
||||
public void close () {
|
||||
impl.close();
|
||||
}
|
||||
|
||||
public InputStream getRequestBody () {
|
||||
return impl.getRequestBody();
|
||||
}
|
||||
|
||||
public int getResponseCode () {
|
||||
return impl.getResponseCode();
|
||||
}
|
||||
|
||||
public OutputStream getResponseBody () {
|
||||
return impl.getResponseBody();
|
||||
}
|
||||
|
||||
|
||||
public void sendResponseHeaders (int rCode, long contentLen)
|
||||
throws IOException
|
||||
{
|
||||
impl.sendResponseHeaders (rCode, contentLen);
|
||||
}
|
||||
|
||||
public InetSocketAddress getRemoteAddress (){
|
||||
return impl.getRemoteAddress();
|
||||
}
|
||||
|
||||
public InetSocketAddress getLocalAddress (){
|
||||
return impl.getLocalAddress();
|
||||
}
|
||||
|
||||
public String getProtocol (){
|
||||
return impl.getProtocol();
|
||||
}
|
||||
|
||||
public Object getAttribute (String name) {
|
||||
return impl.getAttribute (name);
|
||||
}
|
||||
|
||||
public void setAttribute (String name, Object value) {
|
||||
impl.setAttribute (name, value);
|
||||
}
|
||||
|
||||
public void setStreams (InputStream i, OutputStream o) {
|
||||
impl.setStreams (i, o);
|
||||
}
|
||||
|
||||
public HttpPrincipal getPrincipal () {
|
||||
return impl.getPrincipal();
|
||||
}
|
||||
|
||||
ExchangeImpl getExchangeImpl () {
|
||||
return impl;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.security.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import javax.net.ssl.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
public class HttpServerImpl extends HttpServer {
|
||||
|
||||
ServerImpl server;
|
||||
|
||||
HttpServerImpl () throws IOException {
|
||||
this (new InetSocketAddress(80), 0);
|
||||
}
|
||||
|
||||
HttpServerImpl (
|
||||
InetSocketAddress addr, int backlog
|
||||
) throws IOException {
|
||||
server = new ServerImpl (this, "http", addr, backlog);
|
||||
}
|
||||
|
||||
public void bind (InetSocketAddress addr, int backlog) throws IOException {
|
||||
server.bind (addr, backlog);
|
||||
}
|
||||
|
||||
public void start () {
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void setExecutor (Executor executor) {
|
||||
server.setExecutor(executor);
|
||||
}
|
||||
|
||||
public Executor getExecutor () {
|
||||
return server.getExecutor();
|
||||
}
|
||||
|
||||
public void stop (int delay) {
|
||||
server.stop (delay);
|
||||
}
|
||||
|
||||
public HttpContextImpl createContext (String path, HttpHandler handler) {
|
||||
return server.createContext (path, handler);
|
||||
}
|
||||
|
||||
public HttpContextImpl createContext (String path) {
|
||||
return server.createContext (path);
|
||||
}
|
||||
|
||||
public void removeContext (String path) throws IllegalArgumentException {
|
||||
server.removeContext (path);
|
||||
}
|
||||
|
||||
public void removeContext (HttpContext context) throws IllegalArgumentException {
|
||||
server.removeContext (context);
|
||||
}
|
||||
|
||||
public InetSocketAddress getAddress() {
|
||||
return server.getAddress();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.util.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
class HttpsExchangeImpl extends HttpsExchange {
|
||||
|
||||
ExchangeImpl impl;
|
||||
|
||||
HttpsExchangeImpl (ExchangeImpl impl) throws IOException {
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
public Headers getRequestHeaders () {
|
||||
return impl.getRequestHeaders();
|
||||
}
|
||||
|
||||
public Headers getResponseHeaders () {
|
||||
return impl.getResponseHeaders();
|
||||
}
|
||||
|
||||
public URI getRequestURI () {
|
||||
return impl.getRequestURI();
|
||||
}
|
||||
|
||||
public String getRequestMethod (){
|
||||
return impl.getRequestMethod();
|
||||
}
|
||||
|
||||
public HttpContextImpl getHttpContext (){
|
||||
return impl.getHttpContext();
|
||||
}
|
||||
|
||||
public void close () {
|
||||
impl.close();
|
||||
}
|
||||
|
||||
public InputStream getRequestBody () {
|
||||
return impl.getRequestBody();
|
||||
}
|
||||
|
||||
public int getResponseCode () {
|
||||
return impl.getResponseCode();
|
||||
}
|
||||
|
||||
public OutputStream getResponseBody () {
|
||||
return impl.getResponseBody();
|
||||
}
|
||||
|
||||
|
||||
public void sendResponseHeaders (int rCode, long contentLen)
|
||||
throws IOException
|
||||
{
|
||||
impl.sendResponseHeaders (rCode, contentLen);
|
||||
}
|
||||
|
||||
public InetSocketAddress getRemoteAddress (){
|
||||
return impl.getRemoteAddress();
|
||||
}
|
||||
|
||||
public InetSocketAddress getLocalAddress (){
|
||||
return impl.getLocalAddress();
|
||||
}
|
||||
|
||||
public String getProtocol (){
|
||||
return impl.getProtocol();
|
||||
}
|
||||
|
||||
public SSLSession getSSLSession () {
|
||||
return impl.getSSLSession ();
|
||||
}
|
||||
|
||||
public Object getAttribute (String name) {
|
||||
return impl.getAttribute (name);
|
||||
}
|
||||
|
||||
public void setAttribute (String name, Object value) {
|
||||
impl.setAttribute (name, value);
|
||||
}
|
||||
|
||||
public void setStreams (InputStream i, OutputStream o) {
|
||||
impl.setStreams (i, o);
|
||||
}
|
||||
|
||||
public HttpPrincipal getPrincipal () {
|
||||
return impl.getPrincipal();
|
||||
}
|
||||
|
||||
ExchangeImpl getExchangeImpl () {
|
||||
return impl;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.security.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import javax.net.ssl.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
public class HttpsServerImpl extends HttpsServer {
|
||||
|
||||
ServerImpl server;
|
||||
|
||||
HttpsServerImpl () throws IOException {
|
||||
this (new InetSocketAddress(443), 0);
|
||||
}
|
||||
|
||||
HttpsServerImpl (
|
||||
InetSocketAddress addr, int backlog
|
||||
) throws IOException {
|
||||
server = new ServerImpl (this, "https", addr, backlog);
|
||||
}
|
||||
|
||||
public void setHttpsConfigurator (HttpsConfigurator config) {
|
||||
server.setHttpsConfigurator (config);
|
||||
}
|
||||
|
||||
public HttpsConfigurator getHttpsConfigurator () {
|
||||
return server.getHttpsConfigurator();
|
||||
}
|
||||
|
||||
public void bind (InetSocketAddress addr, int backlog) throws IOException {
|
||||
server.bind (addr, backlog);
|
||||
}
|
||||
|
||||
public void start () {
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void setExecutor (Executor executor) {
|
||||
server.setExecutor(executor);
|
||||
}
|
||||
|
||||
public Executor getExecutor () {
|
||||
return server.getExecutor();
|
||||
}
|
||||
|
||||
public void stop (int delay) {
|
||||
server.stop (delay);
|
||||
}
|
||||
|
||||
public HttpContextImpl createContext (String path, HttpHandler handler) {
|
||||
return server.createContext (path, handler);
|
||||
}
|
||||
|
||||
public HttpContextImpl createContext (String path) {
|
||||
return server.createContext (path);
|
||||
}
|
||||
|
||||
public void removeContext (String path) throws IllegalArgumentException {
|
||||
server.removeContext (path);
|
||||
}
|
||||
|
||||
public void removeContext (HttpContext context) throws IllegalArgumentException {
|
||||
server.removeContext (context);
|
||||
}
|
||||
|
||||
public InetSocketAddress getAddress() {
|
||||
return server.getAddress();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* a (filter) input stream which can tell us if bytes are "left over"
|
||||
* on the underlying stream which can be read (without blocking)
|
||||
* on another instance of this class.
|
||||
*
|
||||
* The class can also report if all bytes "expected" to be read
|
||||
* were read, by the time close() was called. In that case,
|
||||
* bytes may be drained to consume them (by calling drain() ).
|
||||
*
|
||||
* isEOF() returns true, when all expected bytes have been read
|
||||
*/
|
||||
abstract class LeftOverInputStream extends FilterInputStream {
|
||||
final ExchangeImpl t;
|
||||
final ServerImpl server;
|
||||
protected boolean closed = false;
|
||||
protected boolean eof = false;
|
||||
byte[] one = new byte [1];
|
||||
|
||||
public LeftOverInputStream (ExchangeImpl t, InputStream src) {
|
||||
super (src);
|
||||
this.t = t;
|
||||
this.server = t.getServerImpl();
|
||||
}
|
||||
/**
|
||||
* if bytes are left over buffered on *the UNDERLYING* stream
|
||||
*/
|
||||
public boolean isDataBuffered () throws IOException {
|
||||
assert eof;
|
||||
return super.available() > 0;
|
||||
}
|
||||
|
||||
public void close () throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
if (!eof) {
|
||||
eof = drain (ServerConfig.getDrainAmount());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed () {
|
||||
return closed;
|
||||
}
|
||||
|
||||
public boolean isEOF () {
|
||||
return eof;
|
||||
}
|
||||
|
||||
protected abstract int readImpl (byte[]b, int off, int len) throws IOException;
|
||||
|
||||
public synchronized int read () throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("Stream is closed");
|
||||
}
|
||||
int c = readImpl (one, 0, 1);
|
||||
if (c == -1 || c == 0) {
|
||||
return c;
|
||||
} else {
|
||||
return one[0] & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int read (byte[]b, int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("Stream is closed");
|
||||
}
|
||||
return readImpl (b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* read and discard up to l bytes or "eof" occurs,
|
||||
* (whichever is first). Then return true if the stream
|
||||
* is at eof (ie. all bytes were read) or false if not
|
||||
* (still bytes to be read)
|
||||
*/
|
||||
public boolean drain (long l) throws IOException {
|
||||
int bufSize = 2048;
|
||||
byte[] db = new byte [bufSize];
|
||||
while (l > 0) {
|
||||
if (server.isFinishing()) {
|
||||
break;
|
||||
}
|
||||
long len = readImpl (db, 0, bufSize);
|
||||
if (len == -1) {
|
||||
eof = true;
|
||||
return true;
|
||||
} else {
|
||||
l = l - len;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
406
src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java
Normal file
406
src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java
Normal file
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.nio.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Request {
|
||||
|
||||
final static int BUF_LEN = 2048;
|
||||
final static byte CR = 13;
|
||||
final static byte LF = 10;
|
||||
|
||||
private String startLine;
|
||||
private SocketChannel chan;
|
||||
private InputStream is;
|
||||
private OutputStream os;
|
||||
|
||||
Request (InputStream rawInputStream, OutputStream rawout) throws IOException {
|
||||
is = rawInputStream;
|
||||
os = rawout;
|
||||
do {
|
||||
startLine = readLine();
|
||||
if (startLine == null) {
|
||||
return;
|
||||
}
|
||||
/* skip blank lines */
|
||||
} while (startLine == null ? false : startLine.equals (""));
|
||||
}
|
||||
|
||||
|
||||
char[] buf = new char [BUF_LEN];
|
||||
int pos;
|
||||
StringBuffer lineBuf;
|
||||
|
||||
public InputStream inputStream () {
|
||||
return is;
|
||||
}
|
||||
|
||||
public OutputStream outputStream () {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a line from the stream returning as a String.
|
||||
* Not used for reading headers.
|
||||
*/
|
||||
|
||||
public String readLine () throws IOException {
|
||||
boolean gotCR = false, gotLF = false;
|
||||
pos = 0; lineBuf = new StringBuffer();
|
||||
while (!gotLF) {
|
||||
int c = is.read();
|
||||
if (c == -1) {
|
||||
return null;
|
||||
}
|
||||
if (gotCR) {
|
||||
if (c == LF) {
|
||||
gotLF = true;
|
||||
} else {
|
||||
gotCR = false;
|
||||
consume (CR);
|
||||
consume (c);
|
||||
}
|
||||
} else {
|
||||
if (c == CR) {
|
||||
gotCR = true;
|
||||
} else {
|
||||
consume (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
lineBuf.append (buf, 0, pos);
|
||||
return new String (lineBuf);
|
||||
}
|
||||
|
||||
private void consume (int c) {
|
||||
if (pos == BUF_LEN) {
|
||||
lineBuf.append (buf);
|
||||
pos = 0;
|
||||
}
|
||||
buf[pos++] = (char)c;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the request line (first line of a request)
|
||||
*/
|
||||
public String requestLine () {
|
||||
return startLine;
|
||||
}
|
||||
|
||||
Headers hdrs = null;
|
||||
@SuppressWarnings("fallthrough")
|
||||
Headers headers () throws IOException {
|
||||
if (hdrs != null) {
|
||||
return hdrs;
|
||||
}
|
||||
hdrs = new Headers();
|
||||
|
||||
char s[] = new char[10];
|
||||
int len = 0;
|
||||
|
||||
int firstc = is.read();
|
||||
|
||||
// check for empty headers
|
||||
if (firstc == CR || firstc == LF) {
|
||||
int c = is.read();
|
||||
if (c == CR || c == LF) {
|
||||
return hdrs;
|
||||
}
|
||||
s[0] = (char)firstc;
|
||||
len = 1;
|
||||
firstc = c;
|
||||
}
|
||||
|
||||
while (firstc != LF && firstc != CR && firstc >= 0) {
|
||||
int keyend = -1;
|
||||
int c;
|
||||
boolean inKey = firstc > ' ';
|
||||
s[len++] = (char) firstc;
|
||||
parseloop:{
|
||||
while ((c = is.read()) >= 0) {
|
||||
switch (c) {
|
||||
/*fallthrough*/
|
||||
case ':':
|
||||
if (inKey && len > 0)
|
||||
keyend = len;
|
||||
inKey = false;
|
||||
break;
|
||||
case '\t':
|
||||
c = ' ';
|
||||
case ' ':
|
||||
inKey = false;
|
||||
break;
|
||||
case CR:
|
||||
case LF:
|
||||
firstc = is.read();
|
||||
if (c == CR && firstc == LF) {
|
||||
firstc = is.read();
|
||||
if (firstc == CR)
|
||||
firstc = is.read();
|
||||
}
|
||||
if (firstc == LF || firstc == CR || firstc > ' ')
|
||||
break parseloop;
|
||||
/* continuation */
|
||||
c = ' ';
|
||||
break;
|
||||
}
|
||||
if (len >= s.length) {
|
||||
char ns[] = new char[s.length * 2];
|
||||
System.arraycopy(s, 0, ns, 0, len);
|
||||
s = ns;
|
||||
}
|
||||
s[len++] = (char) c;
|
||||
}
|
||||
firstc = -1;
|
||||
}
|
||||
while (len > 0 && s[len - 1] <= ' ')
|
||||
len--;
|
||||
String k;
|
||||
if (keyend <= 0) {
|
||||
k = null;
|
||||
keyend = 0;
|
||||
} else {
|
||||
k = String.copyValueOf(s, 0, keyend);
|
||||
if (keyend < len && s[keyend] == ':')
|
||||
keyend++;
|
||||
while (keyend < len && s[keyend] <= ' ')
|
||||
keyend++;
|
||||
}
|
||||
String v;
|
||||
if (keyend >= len)
|
||||
v = new String();
|
||||
else
|
||||
v = String.copyValueOf(s, keyend, len - keyend);
|
||||
|
||||
if (hdrs.size() >= ServerConfig.getMaxReqHeaders()) {
|
||||
throw new IOException("Maximum number of request headers (" +
|
||||
"sun.net.httpserver.maxReqHeaders) exceeded, " +
|
||||
ServerConfig.getMaxReqHeaders() + ".");
|
||||
}
|
||||
|
||||
hdrs.add (k,v);
|
||||
len = 0;
|
||||
}
|
||||
return hdrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements blocking reading semantics on top of a non-blocking channel
|
||||
*/
|
||||
|
||||
static class ReadStream extends InputStream {
|
||||
SocketChannel channel;
|
||||
ByteBuffer chanbuf;
|
||||
byte[] one;
|
||||
private boolean closed = false, eof = false;
|
||||
ByteBuffer markBuf; /* reads may be satisfied from this buffer */
|
||||
boolean marked;
|
||||
boolean reset;
|
||||
int readlimit;
|
||||
static long readTimeout;
|
||||
ServerImpl server;
|
||||
final static int BUFSIZE = 8 * 1024;
|
||||
|
||||
public ReadStream (ServerImpl server, SocketChannel chan) throws IOException {
|
||||
this.channel = chan;
|
||||
this.server = server;
|
||||
chanbuf = ByteBuffer.allocate (BUFSIZE);
|
||||
chanbuf.clear();
|
||||
one = new byte[1];
|
||||
closed = marked = reset = false;
|
||||
}
|
||||
|
||||
public synchronized int read (byte[] b) throws IOException {
|
||||
return read (b, 0, b.length);
|
||||
}
|
||||
|
||||
public synchronized int read () throws IOException {
|
||||
int result = read (one, 0, 1);
|
||||
if (result == 1) {
|
||||
return one[0] & 0xFF;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int read (byte[] b, int off, int srclen) throws IOException {
|
||||
|
||||
int canreturn, willreturn;
|
||||
|
||||
if (closed)
|
||||
throw new IOException ("Stream closed");
|
||||
|
||||
if (eof) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert channel.isBlocking();
|
||||
|
||||
if (off < 0 || srclen < 0|| srclen > (b.length-off)) {
|
||||
throw new IndexOutOfBoundsException ();
|
||||
}
|
||||
|
||||
if (reset) { /* satisfy from markBuf */
|
||||
canreturn = markBuf.remaining ();
|
||||
willreturn = canreturn>srclen ? srclen : canreturn;
|
||||
markBuf.get(b, off, willreturn);
|
||||
if (canreturn == willreturn) {
|
||||
reset = false;
|
||||
}
|
||||
} else { /* satisfy from channel */
|
||||
chanbuf.clear ();
|
||||
if (srclen < BUFSIZE) {
|
||||
chanbuf.limit (srclen);
|
||||
}
|
||||
do {
|
||||
willreturn = channel.read (chanbuf);
|
||||
} while (willreturn == 0);
|
||||
if (willreturn == -1) {
|
||||
eof = true;
|
||||
return -1;
|
||||
}
|
||||
chanbuf.flip ();
|
||||
chanbuf.get(b, off, willreturn);
|
||||
|
||||
if (marked) { /* copy into markBuf */
|
||||
try {
|
||||
markBuf.put (b, off, willreturn);
|
||||
} catch (BufferOverflowException e) {
|
||||
marked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return willreturn;
|
||||
}
|
||||
|
||||
public boolean markSupported () {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Does not query the OS socket */
|
||||
public synchronized int available () throws IOException {
|
||||
if (closed)
|
||||
throw new IOException ("Stream is closed");
|
||||
|
||||
if (eof)
|
||||
return -1;
|
||||
|
||||
if (reset)
|
||||
return markBuf.remaining();
|
||||
|
||||
return chanbuf.remaining();
|
||||
}
|
||||
|
||||
public void close () throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
channel.close ();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
public synchronized void mark (int readlimit) {
|
||||
if (closed)
|
||||
return;
|
||||
this.readlimit = readlimit;
|
||||
markBuf = ByteBuffer.allocate (readlimit);
|
||||
marked = true;
|
||||
reset = false;
|
||||
}
|
||||
|
||||
public synchronized void reset () throws IOException {
|
||||
if (closed )
|
||||
return;
|
||||
if (!marked)
|
||||
throw new IOException ("Stream not marked");
|
||||
marked = false;
|
||||
reset = true;
|
||||
markBuf.flip ();
|
||||
}
|
||||
}
|
||||
|
||||
static class WriteStream extends java.io.OutputStream {
|
||||
SocketChannel channel;
|
||||
ByteBuffer buf;
|
||||
SelectionKey key;
|
||||
boolean closed;
|
||||
byte[] one;
|
||||
ServerImpl server;
|
||||
|
||||
public WriteStream (ServerImpl server, SocketChannel channel) throws IOException {
|
||||
this.channel = channel;
|
||||
this.server = server;
|
||||
assert channel.isBlocking();
|
||||
closed = false;
|
||||
one = new byte [1];
|
||||
buf = ByteBuffer.allocate (4096);
|
||||
}
|
||||
|
||||
public synchronized void write (int b) throws IOException {
|
||||
one[0] = (byte)b;
|
||||
write (one, 0, 1);
|
||||
}
|
||||
|
||||
public synchronized void write (byte[] b) throws IOException {
|
||||
write (b, 0, b.length);
|
||||
}
|
||||
|
||||
public synchronized void write (byte[] b, int off, int len) throws IOException {
|
||||
int l = len;
|
||||
if (closed)
|
||||
throw new IOException ("stream is closed");
|
||||
|
||||
int cap = buf.capacity();
|
||||
if (cap < len) {
|
||||
int diff = len - cap;
|
||||
buf = ByteBuffer.allocate (2*(cap+diff));
|
||||
}
|
||||
buf.clear();
|
||||
buf.put (b, off, len);
|
||||
buf.flip ();
|
||||
int n;
|
||||
while ((n = channel.write (buf)) < l) {
|
||||
l -= n;
|
||||
if (l == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void close () throws IOException {
|
||||
if (closed)
|
||||
return;
|
||||
//server.logStackTrace ("Request.OS.close: isOpen="+channel.isOpen());
|
||||
channel.close ();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,660 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.locks.*;
|
||||
import javax.net.ssl.*;
|
||||
import javax.net.ssl.SSLEngineResult.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
/**
|
||||
* given a non-blocking SocketChannel, it produces
|
||||
* (blocking) streams which encrypt/decrypt the SSL content
|
||||
* and handle the SSL handshaking automatically.
|
||||
*/
|
||||
|
||||
class SSLStreams {
|
||||
|
||||
SSLContext sslctx;
|
||||
SocketChannel chan;
|
||||
TimeSource time;
|
||||
ServerImpl server;
|
||||
SSLEngine engine;
|
||||
EngineWrapper wrapper;
|
||||
OutputStream os;
|
||||
InputStream is;
|
||||
|
||||
/* held by thread doing the hand-shake on this connection */
|
||||
Lock handshaking = new ReentrantLock();
|
||||
|
||||
SSLStreams (ServerImpl server, SSLContext sslctx, SocketChannel chan) throws IOException {
|
||||
this.server = server;
|
||||
this.time= (TimeSource)server;
|
||||
this.sslctx= sslctx;
|
||||
this.chan= chan;
|
||||
InetSocketAddress addr =
|
||||
(InetSocketAddress)chan.socket().getRemoteSocketAddress();
|
||||
engine = sslctx.createSSLEngine (addr.getHostName(), addr.getPort());
|
||||
engine.setUseClientMode (false);
|
||||
HttpsConfigurator cfg = server.getHttpsConfigurator();
|
||||
configureEngine (cfg, addr);
|
||||
wrapper = new EngineWrapper (chan, engine);
|
||||
}
|
||||
|
||||
private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){
|
||||
if (cfg != null) {
|
||||
Parameters params = new Parameters (cfg, addr);
|
||||
//BEGIN_TIGER_EXCLUDE
|
||||
cfg.configure (params);
|
||||
SSLParameters sslParams = params.getSSLParameters();
|
||||
if (sslParams != null) {
|
||||
engine.setSSLParameters (sslParams);
|
||||
} else
|
||||
//END_TIGER_EXCLUDE
|
||||
{
|
||||
/* tiger compatibility */
|
||||
if (params.getCipherSuites() != null) {
|
||||
try {
|
||||
engine.setEnabledCipherSuites (
|
||||
params.getCipherSuites()
|
||||
);
|
||||
} catch (IllegalArgumentException e) { /* LOG */}
|
||||
}
|
||||
engine.setNeedClientAuth (params.getNeedClientAuth());
|
||||
engine.setWantClientAuth (params.getWantClientAuth());
|
||||
if (params.getProtocols() != null) {
|
||||
try {
|
||||
engine.setEnabledProtocols (
|
||||
params.getProtocols()
|
||||
);
|
||||
} catch (IllegalArgumentException e) { /* LOG */}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Parameters extends HttpsParameters {
|
||||
InetSocketAddress addr;
|
||||
HttpsConfigurator cfg;
|
||||
|
||||
Parameters (HttpsConfigurator cfg, InetSocketAddress addr) {
|
||||
this.addr = addr;
|
||||
this.cfg = cfg;
|
||||
}
|
||||
public InetSocketAddress getClientAddress () {
|
||||
return addr;
|
||||
}
|
||||
public HttpsConfigurator getHttpsConfigurator() {
|
||||
return cfg;
|
||||
}
|
||||
//BEGIN_TIGER_EXCLUDE
|
||||
SSLParameters params;
|
||||
public void setSSLParameters (SSLParameters p) {
|
||||
params = p;
|
||||
}
|
||||
SSLParameters getSSLParameters () {
|
||||
return params;
|
||||
}
|
||||
//END_TIGER_EXCLUDE
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup resources allocated inside this object
|
||||
*/
|
||||
void close () throws IOException {
|
||||
wrapper.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the SSL InputStream
|
||||
*/
|
||||
InputStream getInputStream () throws IOException {
|
||||
if (is == null) {
|
||||
is = new InputStream();
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the SSL OutputStream
|
||||
*/
|
||||
OutputStream getOutputStream () throws IOException {
|
||||
if (os == null) {
|
||||
os = new OutputStream();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
SSLEngine getSSLEngine () {
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* request the engine to repeat the handshake on this session
|
||||
* the handshake must be driven by reads/writes on the streams
|
||||
* Normally, not necessary to call this.
|
||||
*/
|
||||
void beginHandshake() throws SSLException {
|
||||
engine.beginHandshake();
|
||||
}
|
||||
|
||||
class WrapperResult {
|
||||
SSLEngineResult result;
|
||||
|
||||
/* if passed in buffer was not big enough then the
|
||||
* a reallocated buffer is returned here
|
||||
*/
|
||||
ByteBuffer buf;
|
||||
}
|
||||
|
||||
int app_buf_size;
|
||||
int packet_buf_size;
|
||||
|
||||
enum BufType {
|
||||
PACKET, APPLICATION
|
||||
};
|
||||
|
||||
private ByteBuffer allocate (BufType type) {
|
||||
return allocate (type, -1);
|
||||
}
|
||||
|
||||
private ByteBuffer allocate (BufType type, int len) {
|
||||
assert engine != null;
|
||||
synchronized (this) {
|
||||
int size;
|
||||
if (type == BufType.PACKET) {
|
||||
if (packet_buf_size == 0) {
|
||||
SSLSession sess = engine.getSession();
|
||||
packet_buf_size = sess.getPacketBufferSize();
|
||||
}
|
||||
if (len > packet_buf_size) {
|
||||
packet_buf_size = len;
|
||||
}
|
||||
size = packet_buf_size;
|
||||
} else {
|
||||
if (app_buf_size == 0) {
|
||||
SSLSession sess = engine.getSession();
|
||||
app_buf_size = sess.getApplicationBufferSize();
|
||||
}
|
||||
if (len > app_buf_size) {
|
||||
app_buf_size = len;
|
||||
}
|
||||
size = app_buf_size;
|
||||
}
|
||||
return ByteBuffer.allocate (size);
|
||||
}
|
||||
}
|
||||
|
||||
/* reallocates the buffer by :-
|
||||
* 1. creating a new buffer double the size of the old one
|
||||
* 2. putting the contents of the old buffer into the new one
|
||||
* 3. set xx_buf_size to the new size if it was smaller than new size
|
||||
*
|
||||
* flip is set to true if the old buffer needs to be flipped
|
||||
* before it is copied.
|
||||
*/
|
||||
private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) {
|
||||
synchronized (this) {
|
||||
int nsize = 2 * b.capacity();
|
||||
ByteBuffer n = allocate (type, nsize);
|
||||
if (flip) {
|
||||
b.flip();
|
||||
}
|
||||
n.put(b);
|
||||
b = n;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
/**
|
||||
* This is a thin wrapper over SSLEngine and the SocketChannel,
|
||||
* which guarantees the ordering of wraps/unwraps with respect to the underlying
|
||||
* channel read/writes. It handles the UNDER/OVERFLOW status codes
|
||||
* It does not handle the handshaking status codes, or the CLOSED status code
|
||||
* though once the engine is closed, any attempt to read/write to it
|
||||
* will get an exception. The overall result is returned.
|
||||
* It functions synchronously/blocking
|
||||
*/
|
||||
class EngineWrapper {
|
||||
|
||||
SocketChannel chan;
|
||||
SSLEngine engine;
|
||||
Object wrapLock, unwrapLock;
|
||||
ByteBuffer unwrap_src, wrap_dst;
|
||||
boolean closed = false;
|
||||
int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
|
||||
|
||||
EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
|
||||
this.chan = chan;
|
||||
this.engine = engine;
|
||||
wrapLock = new Object();
|
||||
unwrapLock = new Object();
|
||||
unwrap_src = allocate(BufType.PACKET);
|
||||
wrap_dst = allocate(BufType.PACKET);
|
||||
}
|
||||
|
||||
void close () throws IOException {
|
||||
}
|
||||
|
||||
/* try to wrap and send the data in src. Handles OVERFLOW.
|
||||
* Might block if there is an outbound blockage or if another
|
||||
* thread is calling wrap(). Also, might not send any data
|
||||
* if an unwrap is needed.
|
||||
*/
|
||||
WrapperResult wrapAndSend(ByteBuffer src) throws IOException {
|
||||
return wrapAndSendX(src, false);
|
||||
}
|
||||
|
||||
WrapperResult wrapAndSendX(ByteBuffer src, boolean ignoreClose) throws IOException {
|
||||
if (closed && !ignoreClose) {
|
||||
throw new IOException ("Engine is closed");
|
||||
}
|
||||
Status status;
|
||||
WrapperResult r = new WrapperResult();
|
||||
synchronized (wrapLock) {
|
||||
wrap_dst.clear();
|
||||
do {
|
||||
r.result = engine.wrap (src, wrap_dst);
|
||||
status = r.result.getStatus();
|
||||
if (status == Status.BUFFER_OVERFLOW) {
|
||||
wrap_dst = realloc (wrap_dst, true, BufType.PACKET);
|
||||
}
|
||||
} while (status == Status.BUFFER_OVERFLOW);
|
||||
if (status == Status.CLOSED && !ignoreClose) {
|
||||
closed = true;
|
||||
return r;
|
||||
}
|
||||
if (r.result.bytesProduced() > 0) {
|
||||
wrap_dst.flip();
|
||||
int l = wrap_dst.remaining();
|
||||
assert l == r.result.bytesProduced();
|
||||
while (l>0) {
|
||||
l -= chan.write (wrap_dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* block until a complete message is available and return it
|
||||
* in dst, together with the Result. dst may have been re-allocated
|
||||
* so caller should check the returned value in Result
|
||||
* If handshaking is in progress then, possibly no data is returned
|
||||
*/
|
||||
WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
|
||||
Status status = Status.OK;
|
||||
WrapperResult r = new WrapperResult();
|
||||
r.buf = dst;
|
||||
if (closed) {
|
||||
throw new IOException ("Engine is closed");
|
||||
}
|
||||
boolean needData;
|
||||
if (u_remaining > 0) {
|
||||
unwrap_src.compact();
|
||||
unwrap_src.flip();
|
||||
needData = false;
|
||||
} else {
|
||||
unwrap_src.clear();
|
||||
needData = true;
|
||||
}
|
||||
synchronized (unwrapLock) {
|
||||
int x;
|
||||
do {
|
||||
if (needData) {
|
||||
do {
|
||||
x = chan.read (unwrap_src);
|
||||
} while (x == 0);
|
||||
if (x == -1) {
|
||||
throw new IOException ("connection closed for reading");
|
||||
}
|
||||
unwrap_src.flip();
|
||||
}
|
||||
r.result = engine.unwrap (unwrap_src, r.buf);
|
||||
status = r.result.getStatus();
|
||||
if (status == Status.BUFFER_UNDERFLOW) {
|
||||
if (unwrap_src.limit() == unwrap_src.capacity()) {
|
||||
/* buffer not big enough */
|
||||
unwrap_src = realloc (
|
||||
unwrap_src, false, BufType.PACKET
|
||||
);
|
||||
} else {
|
||||
/* Buffer not full, just need to read more
|
||||
* data off the channel. Reset pointers
|
||||
* for reading off SocketChannel
|
||||
*/
|
||||
unwrap_src.position (unwrap_src.limit());
|
||||
unwrap_src.limit (unwrap_src.capacity());
|
||||
}
|
||||
needData = true;
|
||||
} else if (status == Status.BUFFER_OVERFLOW) {
|
||||
r.buf = realloc (r.buf, true, BufType.APPLICATION);
|
||||
needData = false;
|
||||
} else if (status == Status.CLOSED) {
|
||||
closed = true;
|
||||
r.buf.flip();
|
||||
return r;
|
||||
}
|
||||
} while (status != Status.OK);
|
||||
}
|
||||
u_remaining = unwrap_src.remaining();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send the data in the given ByteBuffer. If a handshake is needed
|
||||
* then this is handled within this method. When this call returns,
|
||||
* all of the given user data has been sent and any handshake has been
|
||||
* completed. Caller should check if engine has been closed.
|
||||
*/
|
||||
public WrapperResult sendData (ByteBuffer src) throws IOException {
|
||||
WrapperResult r=null;
|
||||
while (src.remaining() > 0) {
|
||||
r = wrapper.wrapAndSend(src);
|
||||
Status status = r.result.getStatus();
|
||||
if (status == Status.CLOSED) {
|
||||
doClosure ();
|
||||
return r;
|
||||
}
|
||||
HandshakeStatus hs_status = r.result.getHandshakeStatus();
|
||||
if (hs_status != HandshakeStatus.FINISHED &&
|
||||
hs_status != HandshakeStatus.NOT_HANDSHAKING)
|
||||
{
|
||||
doHandshake(hs_status);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* read data thru the engine into the given ByteBuffer. If the
|
||||
* given buffer was not large enough, a new one is allocated
|
||||
* and returned. This call handles handshaking automatically.
|
||||
* Caller should check if engine has been closed.
|
||||
*/
|
||||
public WrapperResult recvData (ByteBuffer dst) throws IOException {
|
||||
/* we wait until some user data arrives */
|
||||
WrapperResult r = null;
|
||||
assert dst.position() == 0;
|
||||
while (dst.position() == 0) {
|
||||
r = wrapper.recvAndUnwrap (dst);
|
||||
dst = (r.buf != dst) ? r.buf: dst;
|
||||
Status status = r.result.getStatus();
|
||||
if (status == Status.CLOSED) {
|
||||
doClosure ();
|
||||
return r;
|
||||
}
|
||||
|
||||
HandshakeStatus hs_status = r.result.getHandshakeStatus();
|
||||
if (hs_status != HandshakeStatus.FINISHED &&
|
||||
hs_status != HandshakeStatus.NOT_HANDSHAKING)
|
||||
{
|
||||
doHandshake (hs_status);
|
||||
}
|
||||
}
|
||||
dst.flip();
|
||||
return r;
|
||||
}
|
||||
|
||||
/* we've received a close notify. Need to call wrap to send
|
||||
* the response
|
||||
*/
|
||||
void doClosure () throws IOException {
|
||||
try {
|
||||
handshaking.lock();
|
||||
ByteBuffer tmp = allocate(BufType.APPLICATION);
|
||||
WrapperResult r;
|
||||
do {
|
||||
tmp.clear();
|
||||
tmp.flip ();
|
||||
r = wrapper.wrapAndSendX (tmp, true);
|
||||
} while (r.result.getStatus() != Status.CLOSED);
|
||||
} finally {
|
||||
handshaking.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/* do the (complete) handshake after acquiring the handshake lock.
|
||||
* If two threads call this at the same time, then we depend
|
||||
* on the wrapper methods being idempotent. eg. if wrapAndSend()
|
||||
* is called with no data to send then there must be no problem
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
void doHandshake (HandshakeStatus hs_status) throws IOException {
|
||||
try {
|
||||
handshaking.lock();
|
||||
ByteBuffer tmp = allocate(BufType.APPLICATION);
|
||||
while (hs_status != HandshakeStatus.FINISHED &&
|
||||
hs_status != HandshakeStatus.NOT_HANDSHAKING)
|
||||
{
|
||||
WrapperResult r = null;
|
||||
switch (hs_status) {
|
||||
case NEED_TASK:
|
||||
Runnable task;
|
||||
while ((task = engine.getDelegatedTask()) != null) {
|
||||
/* run in current thread, because we are already
|
||||
* running an external Executor
|
||||
*/
|
||||
task.run();
|
||||
}
|
||||
/* fall thru - call wrap again */
|
||||
case NEED_WRAP:
|
||||
tmp.clear();
|
||||
tmp.flip();
|
||||
r = wrapper.wrapAndSend(tmp);
|
||||
break;
|
||||
|
||||
case NEED_UNWRAP:
|
||||
tmp.clear();
|
||||
r = wrapper.recvAndUnwrap (tmp);
|
||||
if (r.buf != tmp) {
|
||||
tmp = r.buf;
|
||||
}
|
||||
assert tmp.position() == 0;
|
||||
break;
|
||||
}
|
||||
hs_status = r.result.getHandshakeStatus();
|
||||
}
|
||||
} finally {
|
||||
handshaking.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* represents an SSL input stream. Multiple https requests can
|
||||
* be sent over one stream. closing this stream causes an SSL close
|
||||
* input.
|
||||
*/
|
||||
class InputStream extends java.io.InputStream {
|
||||
|
||||
ByteBuffer bbuf;
|
||||
boolean closed = false;
|
||||
|
||||
/* this stream eof */
|
||||
boolean eof = false;
|
||||
|
||||
boolean needData = true;
|
||||
|
||||
InputStream () {
|
||||
bbuf = allocate (BufType.APPLICATION);
|
||||
}
|
||||
|
||||
public int read (byte[] buf, int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("SSL stream is closed");
|
||||
}
|
||||
if (eof) {
|
||||
return 0;
|
||||
}
|
||||
int available=0;
|
||||
if (!needData) {
|
||||
available = bbuf.remaining();
|
||||
needData = (available==0);
|
||||
}
|
||||
if (needData) {
|
||||
bbuf.clear();
|
||||
WrapperResult r = recvData (bbuf);
|
||||
bbuf = r.buf== bbuf? bbuf: r.buf;
|
||||
if ((available=bbuf.remaining()) == 0) {
|
||||
eof = true;
|
||||
return 0;
|
||||
} else {
|
||||
needData = false;
|
||||
}
|
||||
}
|
||||
/* copy as much as possible from buf into users buf */
|
||||
if (len > available) {
|
||||
len = available;
|
||||
}
|
||||
bbuf.get (buf, off, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
public int available () throws IOException {
|
||||
return bbuf.remaining();
|
||||
}
|
||||
|
||||
public boolean markSupported () {
|
||||
return false; /* not possible with SSLEngine */
|
||||
}
|
||||
|
||||
public void reset () throws IOException {
|
||||
throw new IOException ("mark/reset not supported");
|
||||
}
|
||||
|
||||
public long skip (long s) throws IOException {
|
||||
int n = (int)s;
|
||||
if (closed) {
|
||||
throw new IOException ("SSL stream is closed");
|
||||
}
|
||||
if (eof) {
|
||||
return 0;
|
||||
}
|
||||
int ret = n;
|
||||
while (n > 0) {
|
||||
if (bbuf.remaining() >= n) {
|
||||
bbuf.position (bbuf.position()+n);
|
||||
return ret;
|
||||
} else {
|
||||
n -= bbuf.remaining();
|
||||
bbuf.clear();
|
||||
WrapperResult r = recvData (bbuf);
|
||||
bbuf = r.buf==bbuf? bbuf: r.buf;
|
||||
}
|
||||
}
|
||||
return ret; /* not reached */
|
||||
}
|
||||
|
||||
/**
|
||||
* close the SSL connection. All data must have been consumed
|
||||
* before this is called. Otherwise an exception will be thrown.
|
||||
* [Note. May need to revisit this. not quite the normal close() symantics
|
||||
*/
|
||||
public void close () throws IOException {
|
||||
eof = true;
|
||||
engine.closeInbound ();
|
||||
}
|
||||
|
||||
public int read (byte[] buf) throws IOException {
|
||||
return read (buf, 0, buf.length);
|
||||
}
|
||||
|
||||
byte single[] = new byte [1];
|
||||
|
||||
public int read () throws IOException {
|
||||
int n = read (single, 0, 1);
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return single[0] & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* represents an SSL output stream. plain text data written to this stream
|
||||
* is encrypted by the stream. Multiple HTTPS responses can be sent on
|
||||
* one stream. closing this stream initiates an SSL closure
|
||||
*/
|
||||
class OutputStream extends java.io.OutputStream {
|
||||
ByteBuffer buf;
|
||||
boolean closed = false;
|
||||
byte single[] = new byte[1];
|
||||
|
||||
OutputStream() {
|
||||
buf = allocate(BufType.APPLICATION);
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
single[0] = (byte)b;
|
||||
write (single, 0, 1);
|
||||
}
|
||||
|
||||
public void write(byte b[]) throws IOException {
|
||||
write (b, 0, b.length);
|
||||
}
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("output stream is closed");
|
||||
}
|
||||
while (len > 0) {
|
||||
int l = len > buf.capacity() ? buf.capacity() : len;
|
||||
buf.clear();
|
||||
buf.put (b, off, l);
|
||||
len -= l;
|
||||
off += l;
|
||||
buf.flip();
|
||||
WrapperResult r = sendData (buf);
|
||||
if (r.result.getStatus() == Status.CLOSED) {
|
||||
closed = true;
|
||||
if (len > 0) {
|
||||
throw new IOException ("output stream is closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
WrapperResult r=null;
|
||||
engine.closeOutbound();
|
||||
closed = true;
|
||||
HandshakeStatus stat = HandshakeStatus.NEED_WRAP;
|
||||
buf.clear();
|
||||
while (stat == HandshakeStatus.NEED_WRAP) {
|
||||
r = wrapper.wrapAndSend (buf);
|
||||
stat = r.result.getHandshakeStatus();
|
||||
}
|
||||
assert r.result.getStatus() == Status.CLOSED;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Parameters that users will not likely need to set
|
||||
* but are useful for debugging
|
||||
*/
|
||||
|
||||
class ServerConfig {
|
||||
|
||||
private static final int DEFAULT_CLOCK_TICK = 10000 ; // 10 sec.
|
||||
|
||||
/* These values must be a reasonable multiple of clockTick */
|
||||
private static final long DEFAULT_IDLE_INTERVAL = 30 ; // 5 min
|
||||
private static final int DEFAULT_MAX_IDLE_CONNECTIONS = 200 ;
|
||||
|
||||
private static final long DEFAULT_MAX_REQ_TIME = -1; // default: forever
|
||||
private static final long DEFAULT_MAX_RSP_TIME = -1; // default: forever
|
||||
private static final long DEFAULT_TIMER_MILLIS = 1000;
|
||||
private static final int DEFAULT_MAX_REQ_HEADERS = 200;
|
||||
private static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024;
|
||||
|
||||
private static int clockTick;
|
||||
private static long idleInterval;
|
||||
// The maximum number of bytes to drain from an inputstream
|
||||
private static long drainAmount;
|
||||
private static int maxIdleConnections;
|
||||
// The maximum number of request headers allowable
|
||||
private static int maxReqHeaders;
|
||||
// max time a request or response is allowed to take
|
||||
private static long maxReqTime;
|
||||
private static long maxRspTime;
|
||||
private static long timerMillis;
|
||||
private static boolean debug;
|
||||
|
||||
// the value of the TCP_NODELAY socket-level option
|
||||
private static boolean noDelay;
|
||||
|
||||
static {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run () {
|
||||
idleInterval = Long.getLong("sun.net.httpserver.idleInterval",
|
||||
DEFAULT_IDLE_INTERVAL) * 1000;
|
||||
|
||||
clockTick = Integer.getInteger("sun.net.httpserver.clockTick",
|
||||
DEFAULT_CLOCK_TICK);
|
||||
|
||||
maxIdleConnections = Integer.getInteger(
|
||||
"sun.net.httpserver.maxIdleConnections",
|
||||
DEFAULT_MAX_IDLE_CONNECTIONS);
|
||||
|
||||
drainAmount = Long.getLong("sun.net.httpserver.drainAmount",
|
||||
DEFAULT_DRAIN_AMOUNT);
|
||||
|
||||
maxReqHeaders = Integer.getInteger(
|
||||
"sun.net.httpserver.maxReqHeaders",
|
||||
DEFAULT_MAX_REQ_HEADERS);
|
||||
|
||||
maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime",
|
||||
DEFAULT_MAX_REQ_TIME);
|
||||
|
||||
maxRspTime = Long.getLong("sun.net.httpserver.maxRspTime",
|
||||
DEFAULT_MAX_RSP_TIME);
|
||||
|
||||
timerMillis = Long.getLong("sun.net.httpserver.timerMillis",
|
||||
DEFAULT_TIMER_MILLIS);
|
||||
|
||||
debug = Boolean.getBoolean("sun.net.httpserver.debug");
|
||||
|
||||
noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay");
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static void checkLegacyProperties(final Logger logger) {
|
||||
|
||||
// legacy properties that are no longer used
|
||||
// print a warning to logger if they are set.
|
||||
|
||||
java.security.AccessController.doPrivileged(
|
||||
new PrivilegedAction<Void>() {
|
||||
public Void run () {
|
||||
if (System.getProperty("sun.net.httpserver.readTimeout")
|
||||
!=null)
|
||||
{
|
||||
logger.log (Level.WARNING,
|
||||
"sun.net.httpserver.readTimeout "+
|
||||
"property is no longer used. "+
|
||||
"Use sun.net.httpserver.maxReqTime instead."
|
||||
);
|
||||
}
|
||||
if (System.getProperty("sun.net.httpserver.writeTimeout")
|
||||
!=null)
|
||||
{
|
||||
logger.log (Level.WARNING,
|
||||
"sun.net.httpserver.writeTimeout "+
|
||||
"property is no longer used. Use "+
|
||||
"sun.net.httpserver.maxRspTime instead."
|
||||
);
|
||||
}
|
||||
if (System.getProperty("sun.net.httpserver.selCacheTimeout")
|
||||
!=null)
|
||||
{
|
||||
logger.log (Level.WARNING,
|
||||
"sun.net.httpserver.selCacheTimeout "+
|
||||
"property is no longer used."
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
static boolean debugEnabled() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
static long getIdleInterval() {
|
||||
return idleInterval;
|
||||
}
|
||||
|
||||
static int getClockTick() {
|
||||
return clockTick;
|
||||
}
|
||||
|
||||
static int getMaxIdleConnections() {
|
||||
return maxIdleConnections;
|
||||
}
|
||||
|
||||
static long getDrainAmount() {
|
||||
return drainAmount;
|
||||
}
|
||||
|
||||
static int getMaxReqHeaders() {
|
||||
return maxReqHeaders;
|
||||
}
|
||||
|
||||
static long getMaxReqTime() {
|
||||
return maxReqTime;
|
||||
}
|
||||
|
||||
static long getMaxRspTime() {
|
||||
return maxRspTime;
|
||||
}
|
||||
|
||||
static long getTimerMillis() {
|
||||
return timerMillis;
|
||||
}
|
||||
|
||||
static boolean noDelay() {
|
||||
return noDelay;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,894 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import javax.net.ssl.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.net.httpserver.HttpConnection.State;
|
||||
|
||||
/**
|
||||
* Provides implementation for both HTTP and HTTPS
|
||||
*/
|
||||
class ServerImpl implements TimeSource {
|
||||
|
||||
private String protocol;
|
||||
private boolean https;
|
||||
private Executor executor;
|
||||
private HttpsConfigurator httpsConfig;
|
||||
private SSLContext sslContext;
|
||||
private ContextList contexts;
|
||||
private InetSocketAddress address;
|
||||
private ServerSocketChannel schan;
|
||||
private Selector selector;
|
||||
private SelectionKey listenerKey;
|
||||
private Set<HttpConnection> idleConnections;
|
||||
private Set<HttpConnection> allConnections;
|
||||
/* following two are used to keep track of the times
|
||||
* when a connection/request is first received
|
||||
* and when we start to send the response
|
||||
*/
|
||||
private Set<HttpConnection> reqConnections;
|
||||
private Set<HttpConnection> rspConnections;
|
||||
private List<Event> events;
|
||||
private Object lolock = new Object();
|
||||
private volatile boolean finished = false;
|
||||
private volatile boolean terminating = false;
|
||||
private boolean bound = false;
|
||||
private boolean started = false;
|
||||
private volatile long time; /* current time */
|
||||
private volatile long subticks = 0;
|
||||
private volatile long ticks; /* number of clock ticks since server started */
|
||||
private HttpServer wrapper;
|
||||
|
||||
final static int CLOCK_TICK = ServerConfig.getClockTick();
|
||||
final static long IDLE_INTERVAL = ServerConfig.getIdleInterval();
|
||||
final static int MAX_IDLE_CONNECTIONS = ServerConfig.getMaxIdleConnections();
|
||||
final static long TIMER_MILLIS = ServerConfig.getTimerMillis ();
|
||||
final static long MAX_REQ_TIME=getTimeMillis(ServerConfig.getMaxReqTime());
|
||||
final static long MAX_RSP_TIME=getTimeMillis(ServerConfig.getMaxRspTime());
|
||||
final static boolean timer1Enabled = MAX_REQ_TIME != -1 || MAX_RSP_TIME != -1;
|
||||
|
||||
private Timer timer, timer1;
|
||||
private final Logger logger;
|
||||
private Thread dispatcherThread;
|
||||
|
||||
ServerImpl (
|
||||
HttpServer wrapper, String protocol, InetSocketAddress addr, int backlog
|
||||
) throws IOException {
|
||||
|
||||
this.protocol = protocol;
|
||||
this.wrapper = wrapper;
|
||||
this.logger = System.getLogger ("com.sun.net.httpserver");
|
||||
ServerConfig.checkLegacyProperties (logger);
|
||||
https = protocol.equalsIgnoreCase ("https");
|
||||
this.address = addr;
|
||||
contexts = new ContextList();
|
||||
schan = ServerSocketChannel.open();
|
||||
if (addr != null) {
|
||||
ServerSocket socket = schan.socket();
|
||||
socket.bind (addr, backlog);
|
||||
bound = true;
|
||||
}
|
||||
selector = Selector.open ();
|
||||
schan.configureBlocking (false);
|
||||
listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT);
|
||||
dispatcher = new Dispatcher();
|
||||
idleConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
|
||||
allConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
|
||||
reqConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
|
||||
rspConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
|
||||
time = System.currentTimeMillis();
|
||||
timer = new Timer ("server-timer", true);
|
||||
timer.schedule (new ServerTimerTask(), CLOCK_TICK, CLOCK_TICK);
|
||||
if (timer1Enabled) {
|
||||
timer1 = new Timer ("server-timer1", true);
|
||||
timer1.schedule (new ServerTimerTask1(),TIMER_MILLIS,TIMER_MILLIS);
|
||||
logger.log (Level.DEBUG, "HttpServer timer1 enabled period in ms: ", TIMER_MILLIS);
|
||||
logger.log (Level.DEBUG, "MAX_REQ_TIME: "+MAX_REQ_TIME);
|
||||
logger.log (Level.DEBUG, "MAX_RSP_TIME: "+MAX_RSP_TIME);
|
||||
}
|
||||
events = new LinkedList<Event>();
|
||||
logger.log (Level.DEBUG, "HttpServer created "+protocol+" "+ addr);
|
||||
}
|
||||
|
||||
public void bind (InetSocketAddress addr, int backlog) throws IOException {
|
||||
if (bound) {
|
||||
throw new BindException ("HttpServer already bound");
|
||||
}
|
||||
if (addr == null) {
|
||||
throw new NullPointerException ("null address");
|
||||
}
|
||||
ServerSocket socket = schan.socket();
|
||||
socket.bind (addr, backlog);
|
||||
bound = true;
|
||||
}
|
||||
|
||||
public void start () {
|
||||
if (!bound || started || finished) {
|
||||
throw new IllegalStateException ("server in wrong state");
|
||||
}
|
||||
if (executor == null) {
|
||||
executor = new DefaultExecutor();
|
||||
}
|
||||
dispatcherThread = new Thread(null, dispatcher, "HTTP-Dispatcher", 0, false);
|
||||
started = true;
|
||||
dispatcherThread.start();
|
||||
}
|
||||
|
||||
public void setExecutor (Executor executor) {
|
||||
if (started) {
|
||||
throw new IllegalStateException ("server already started");
|
||||
}
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
private static class DefaultExecutor implements Executor {
|
||||
public void execute (Runnable task) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
public Executor getExecutor () {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public void setHttpsConfigurator (HttpsConfigurator config) {
|
||||
if (config == null) {
|
||||
throw new NullPointerException ("null HttpsConfigurator");
|
||||
}
|
||||
if (started) {
|
||||
throw new IllegalStateException ("server already started");
|
||||
}
|
||||
this.httpsConfig = config;
|
||||
sslContext = config.getSSLContext();
|
||||
}
|
||||
|
||||
public HttpsConfigurator getHttpsConfigurator () {
|
||||
return httpsConfig;
|
||||
}
|
||||
|
||||
public final boolean isFinishing() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
public void stop (int delay) {
|
||||
if (delay < 0) {
|
||||
throw new IllegalArgumentException ("negative delay parameter");
|
||||
}
|
||||
terminating = true;
|
||||
try { schan.close(); } catch (IOException e) {}
|
||||
selector.wakeup();
|
||||
long latest = System.currentTimeMillis() + delay * 1000;
|
||||
while (System.currentTimeMillis() < latest) {
|
||||
delay();
|
||||
if (finished) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
finished = true;
|
||||
selector.wakeup();
|
||||
synchronized (allConnections) {
|
||||
for (HttpConnection c : allConnections) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
allConnections.clear();
|
||||
idleConnections.clear();
|
||||
timer.cancel();
|
||||
if (timer1Enabled) {
|
||||
timer1.cancel();
|
||||
}
|
||||
if (dispatcherThread != null) {
|
||||
try {
|
||||
dispatcherThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.log (Level.TRACE, "ServerImpl.stop: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher dispatcher;
|
||||
|
||||
public synchronized HttpContextImpl createContext (String path, HttpHandler handler) {
|
||||
if (handler == null || path == null) {
|
||||
throw new NullPointerException ("null handler, or path parameter");
|
||||
}
|
||||
HttpContextImpl context = new HttpContextImpl (protocol, path, handler, this);
|
||||
contexts.add (context);
|
||||
logger.log (Level.DEBUG, "context created: " + path);
|
||||
return context;
|
||||
}
|
||||
|
||||
public synchronized HttpContextImpl createContext (String path) {
|
||||
if (path == null) {
|
||||
throw new NullPointerException ("null path parameter");
|
||||
}
|
||||
HttpContextImpl context = new HttpContextImpl (protocol, path, null, this);
|
||||
contexts.add (context);
|
||||
logger.log (Level.DEBUG, "context created: " + path);
|
||||
return context;
|
||||
}
|
||||
|
||||
public synchronized void removeContext (String path) throws IllegalArgumentException {
|
||||
if (path == null) {
|
||||
throw new NullPointerException ("null path parameter");
|
||||
}
|
||||
contexts.remove (protocol, path);
|
||||
logger.log (Level.DEBUG, "context removed: " + path);
|
||||
}
|
||||
|
||||
public synchronized void removeContext (HttpContext context) throws IllegalArgumentException {
|
||||
if (!(context instanceof HttpContextImpl)) {
|
||||
throw new IllegalArgumentException ("wrong HttpContext type");
|
||||
}
|
||||
contexts.remove ((HttpContextImpl)context);
|
||||
logger.log (Level.DEBUG, "context removed: " + context.getPath());
|
||||
}
|
||||
|
||||
public InetSocketAddress getAddress() {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<InetSocketAddress>() {
|
||||
public InetSocketAddress run() {
|
||||
return
|
||||
(InetSocketAddress)schan.socket()
|
||||
.getLocalSocketAddress();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Selector getSelector () {
|
||||
return selector;
|
||||
}
|
||||
|
||||
void addEvent (Event r) {
|
||||
synchronized (lolock) {
|
||||
events.add (r);
|
||||
selector.wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
/* main server listener task */
|
||||
|
||||
class Dispatcher implements Runnable {
|
||||
|
||||
private void handleEvent (Event r) {
|
||||
ExchangeImpl t = r.exchange;
|
||||
HttpConnection c = t.getConnection();
|
||||
try {
|
||||
if (r instanceof WriteFinishedEvent) {
|
||||
|
||||
int exchanges = endExchange();
|
||||
if (terminating && exchanges == 0) {
|
||||
finished = true;
|
||||
}
|
||||
responseCompleted (c);
|
||||
LeftOverInputStream is = t.getOriginalInputStream();
|
||||
if (!is.isEOF()) {
|
||||
t.close = true;
|
||||
}
|
||||
if (t.close || idleConnections.size() >= MAX_IDLE_CONNECTIONS) {
|
||||
c.close();
|
||||
allConnections.remove (c);
|
||||
} else {
|
||||
if (is.isDataBuffered()) {
|
||||
/* don't re-enable the interestops, just handle it */
|
||||
requestStarted (c);
|
||||
handle (c.getChannel(), c);
|
||||
} else {
|
||||
connsToRegister.add (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log (
|
||||
Level.TRACE, "Dispatcher (1)", e
|
||||
);
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
final LinkedList<HttpConnection> connsToRegister =
|
||||
new LinkedList<HttpConnection>();
|
||||
|
||||
void reRegister (HttpConnection c) {
|
||||
/* re-register with selector */
|
||||
try {
|
||||
SocketChannel chan = c.getChannel();
|
||||
chan.configureBlocking (false);
|
||||
SelectionKey key = chan.register (selector, SelectionKey.OP_READ);
|
||||
key.attach (c);
|
||||
c.selectionKey = key;
|
||||
c.time = getTime() + IDLE_INTERVAL;
|
||||
idleConnections.add (c);
|
||||
} catch (IOException e) {
|
||||
dprint(e);
|
||||
logger.log (Level.TRACE, "Dispatcher(8)", e);
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (!finished) {
|
||||
try {
|
||||
List<Event> list = null;
|
||||
synchronized (lolock) {
|
||||
if (events.size() > 0) {
|
||||
list = events;
|
||||
events = new LinkedList<Event>();
|
||||
}
|
||||
}
|
||||
|
||||
if (list != null) {
|
||||
for (Event r: list) {
|
||||
handleEvent (r);
|
||||
}
|
||||
}
|
||||
|
||||
for (HttpConnection c : connsToRegister) {
|
||||
reRegister(c);
|
||||
}
|
||||
connsToRegister.clear();
|
||||
|
||||
selector.select(1000);
|
||||
|
||||
/* process the selected list now */
|
||||
Set<SelectionKey> selected = selector.selectedKeys();
|
||||
Iterator<SelectionKey> iter = selected.iterator();
|
||||
while (iter.hasNext()) {
|
||||
SelectionKey key = iter.next();
|
||||
iter.remove ();
|
||||
if (key.equals (listenerKey)) {
|
||||
if (terminating) {
|
||||
continue;
|
||||
}
|
||||
SocketChannel chan = schan.accept();
|
||||
|
||||
// optimist there's a channel
|
||||
if (chan != null) {
|
||||
// Set TCP_NODELAY, if appropriate
|
||||
if (ServerConfig.noDelay()) {
|
||||
chan.socket().setTcpNoDelay(true);
|
||||
}
|
||||
chan.configureBlocking (false);
|
||||
SelectionKey newkey =
|
||||
chan.register (selector, SelectionKey.OP_READ);
|
||||
HttpConnection c = new HttpConnection ();
|
||||
c.selectionKey = newkey;
|
||||
c.setChannel (chan);
|
||||
newkey.attach (c);
|
||||
requestStarted (c);
|
||||
allConnections.add (c);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (key.isReadable()) {
|
||||
boolean closed;
|
||||
SocketChannel chan = (SocketChannel)key.channel();
|
||||
HttpConnection conn = (HttpConnection)key.attachment();
|
||||
|
||||
key.cancel();
|
||||
chan.configureBlocking (true);
|
||||
if (idleConnections.remove(conn)) {
|
||||
// was an idle connection so add it
|
||||
// to reqConnections set.
|
||||
requestStarted (conn);
|
||||
}
|
||||
handle (chan, conn);
|
||||
} else {
|
||||
assert false;
|
||||
}
|
||||
} catch (CancelledKeyException e) {
|
||||
handleException(key, null);
|
||||
} catch (IOException e) {
|
||||
handleException(key, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// call the selector just to process the cancelled keys
|
||||
selector.selectNow();
|
||||
} catch (IOException e) {
|
||||
logger.log (Level.TRACE, "Dispatcher (4)", e);
|
||||
} catch (Exception e) {
|
||||
logger.log (Level.TRACE, "Dispatcher (7)", e);
|
||||
}
|
||||
}
|
||||
try {selector.close(); } catch (Exception e) {}
|
||||
}
|
||||
|
||||
private void handleException (SelectionKey key, Exception e) {
|
||||
HttpConnection conn = (HttpConnection)key.attachment();
|
||||
if (e != null) {
|
||||
logger.log (Level.TRACE, "Dispatcher (2)", e);
|
||||
}
|
||||
closeConnection(conn);
|
||||
}
|
||||
|
||||
public void handle (SocketChannel chan, HttpConnection conn)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
Exchange t = new Exchange (chan, protocol, conn);
|
||||
executor.execute (t);
|
||||
} catch (HttpError e1) {
|
||||
logger.log (Level.TRACE, "Dispatcher (4)", e1);
|
||||
closeConnection(conn);
|
||||
} catch (IOException e) {
|
||||
logger.log (Level.TRACE, "Dispatcher (5)", e);
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean debug = ServerConfig.debugEnabled ();
|
||||
|
||||
static synchronized void dprint (String s) {
|
||||
if (debug) {
|
||||
System.out.println (s);
|
||||
}
|
||||
}
|
||||
|
||||
static synchronized void dprint (Exception e) {
|
||||
if (debug) {
|
||||
System.out.println (e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Logger getLogger () {
|
||||
return logger;
|
||||
}
|
||||
|
||||
private void closeConnection(HttpConnection conn) {
|
||||
conn.close();
|
||||
allConnections.remove(conn);
|
||||
switch (conn.getState()) {
|
||||
case REQUEST:
|
||||
reqConnections.remove(conn);
|
||||
break;
|
||||
case RESPONSE:
|
||||
rspConnections.remove(conn);
|
||||
break;
|
||||
case IDLE:
|
||||
idleConnections.remove(conn);
|
||||
break;
|
||||
}
|
||||
assert !reqConnections.remove(conn);
|
||||
assert !rspConnections.remove(conn);
|
||||
assert !idleConnections.remove(conn);
|
||||
}
|
||||
|
||||
/* per exchange task */
|
||||
|
||||
class Exchange implements Runnable {
|
||||
SocketChannel chan;
|
||||
HttpConnection connection;
|
||||
HttpContextImpl context;
|
||||
InputStream rawin;
|
||||
OutputStream rawout;
|
||||
String protocol;
|
||||
ExchangeImpl tx;
|
||||
HttpContextImpl ctx;
|
||||
boolean rejected = false;
|
||||
|
||||
Exchange (SocketChannel chan, String protocol, HttpConnection conn) throws IOException {
|
||||
this.chan = chan;
|
||||
this.connection = conn;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public void run () {
|
||||
/* context will be null for new connections */
|
||||
context = connection.getHttpContext();
|
||||
boolean newconnection;
|
||||
SSLEngine engine = null;
|
||||
String requestLine = null;
|
||||
SSLStreams sslStreams = null;
|
||||
try {
|
||||
if (context != null ) {
|
||||
this.rawin = connection.getInputStream();
|
||||
this.rawout = connection.getRawOutputStream();
|
||||
newconnection = false;
|
||||
} else {
|
||||
/* figure out what kind of connection this is */
|
||||
newconnection = true;
|
||||
if (https) {
|
||||
if (sslContext == null) {
|
||||
logger.log (Level.WARNING,
|
||||
"SSL connection received. No https contxt created");
|
||||
throw new HttpError ("No SSL context established");
|
||||
}
|
||||
sslStreams = new SSLStreams (ServerImpl.this, sslContext, chan);
|
||||
rawin = sslStreams.getInputStream();
|
||||
rawout = sslStreams.getOutputStream();
|
||||
engine = sslStreams.getSSLEngine();
|
||||
connection.sslStreams = sslStreams;
|
||||
} else {
|
||||
rawin = new BufferedInputStream(
|
||||
new Request.ReadStream (
|
||||
ServerImpl.this, chan
|
||||
));
|
||||
rawout = new Request.WriteStream (
|
||||
ServerImpl.this, chan
|
||||
);
|
||||
}
|
||||
connection.raw = rawin;
|
||||
connection.rawout = rawout;
|
||||
}
|
||||
Request req = new Request (rawin, rawout);
|
||||
requestLine = req.requestLine();
|
||||
if (requestLine == null) {
|
||||
/* connection closed */
|
||||
closeConnection(connection);
|
||||
return;
|
||||
}
|
||||
int space = requestLine.indexOf (' ');
|
||||
if (space == -1) {
|
||||
reject (Code.HTTP_BAD_REQUEST,
|
||||
requestLine, "Bad request line");
|
||||
return;
|
||||
}
|
||||
String method = requestLine.substring (0, space);
|
||||
int start = space+1;
|
||||
space = requestLine.indexOf(' ', start);
|
||||
if (space == -1) {
|
||||
reject (Code.HTTP_BAD_REQUEST,
|
||||
requestLine, "Bad request line");
|
||||
return;
|
||||
}
|
||||
String uriStr = requestLine.substring (start, space);
|
||||
URI uri = new URI (uriStr);
|
||||
start = space+1;
|
||||
String version = requestLine.substring (start);
|
||||
Headers headers = req.headers();
|
||||
String s = headers.getFirst ("Transfer-encoding");
|
||||
long clen = 0L;
|
||||
if (s !=null && s.equalsIgnoreCase ("chunked")) {
|
||||
clen = -1L;
|
||||
} else {
|
||||
s = headers.getFirst ("Content-Length");
|
||||
if (s != null) {
|
||||
clen = Long.parseLong(s);
|
||||
}
|
||||
if (clen == 0) {
|
||||
requestCompleted (connection);
|
||||
}
|
||||
}
|
||||
ctx = contexts.findContext (protocol, uri.getPath());
|
||||
if (ctx == null) {
|
||||
reject (Code.HTTP_NOT_FOUND,
|
||||
requestLine, "No context found for request");
|
||||
return;
|
||||
}
|
||||
connection.setContext (ctx);
|
||||
if (ctx.getHandler() == null) {
|
||||
reject (Code.HTTP_INTERNAL_ERROR,
|
||||
requestLine, "No handler for context");
|
||||
return;
|
||||
}
|
||||
tx = new ExchangeImpl (
|
||||
method, uri, req, clen, connection
|
||||
);
|
||||
String chdr = headers.getFirst("Connection");
|
||||
Headers rheaders = tx.getResponseHeaders();
|
||||
|
||||
if (chdr != null && chdr.equalsIgnoreCase ("close")) {
|
||||
tx.close = true;
|
||||
}
|
||||
if (version.equalsIgnoreCase ("http/1.0")) {
|
||||
tx.http10 = true;
|
||||
if (chdr == null) {
|
||||
tx.close = true;
|
||||
rheaders.set ("Connection", "close");
|
||||
} else if (chdr.equalsIgnoreCase ("keep-alive")) {
|
||||
rheaders.set ("Connection", "keep-alive");
|
||||
int idle=(int)(ServerConfig.getIdleInterval()/1000);
|
||||
int max=ServerConfig.getMaxIdleConnections();
|
||||
String val = "timeout="+idle+", max="+max;
|
||||
rheaders.set ("Keep-Alive", val);
|
||||
}
|
||||
}
|
||||
|
||||
if (newconnection) {
|
||||
connection.setParameters (
|
||||
rawin, rawout, chan, engine, sslStreams,
|
||||
sslContext, protocol, ctx, rawin
|
||||
);
|
||||
}
|
||||
/* check if client sent an Expect 100 Continue.
|
||||
* In that case, need to send an interim response.
|
||||
* In future API may be modified to allow app to
|
||||
* be involved in this process.
|
||||
*/
|
||||
String exp = headers.getFirst("Expect");
|
||||
if (exp != null && exp.equalsIgnoreCase ("100-continue")) {
|
||||
logReply (100, requestLine, null);
|
||||
sendReply (
|
||||
Code.HTTP_CONTINUE, false, null
|
||||
);
|
||||
}
|
||||
/* uf is the list of filters seen/set by the user.
|
||||
* sf is the list of filters established internally
|
||||
* and which are not visible to the user. uc and sc
|
||||
* are the corresponding Filter.Chains.
|
||||
* They are linked together by a LinkHandler
|
||||
* so that they can both be invoked in one call.
|
||||
*/
|
||||
List<Filter> sf = ctx.getSystemFilters();
|
||||
List<Filter> uf = ctx.getFilters();
|
||||
|
||||
Filter.Chain sc = new Filter.Chain(sf, ctx.getHandler());
|
||||
Filter.Chain uc = new Filter.Chain(uf, new LinkHandler (sc));
|
||||
|
||||
/* set up the two stream references */
|
||||
tx.getRequestBody();
|
||||
tx.getResponseBody();
|
||||
if (https) {
|
||||
uc.doFilter (new HttpsExchangeImpl (tx));
|
||||
} else {
|
||||
uc.doFilter (new HttpExchangeImpl (tx));
|
||||
}
|
||||
|
||||
} catch (IOException e1) {
|
||||
logger.log (Level.TRACE, "ServerImpl.Exchange (1)", e1);
|
||||
closeConnection(connection);
|
||||
} catch (NumberFormatException e3) {
|
||||
reject (Code.HTTP_BAD_REQUEST,
|
||||
requestLine, "NumberFormatException thrown");
|
||||
} catch (URISyntaxException e) {
|
||||
reject (Code.HTTP_BAD_REQUEST,
|
||||
requestLine, "URISyntaxException thrown");
|
||||
} catch (Exception e4) {
|
||||
logger.log (Level.TRACE, "ServerImpl.Exchange (2)", e4);
|
||||
closeConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
/* used to link to 2 or more Filter.Chains together */
|
||||
|
||||
class LinkHandler implements HttpHandler {
|
||||
Filter.Chain nextChain;
|
||||
|
||||
LinkHandler (Filter.Chain nextChain) {
|
||||
this.nextChain = nextChain;
|
||||
}
|
||||
|
||||
public void handle (HttpExchange exchange) throws IOException {
|
||||
nextChain.doFilter (exchange);
|
||||
}
|
||||
}
|
||||
|
||||
void reject (int code, String requestStr, String message) {
|
||||
rejected = true;
|
||||
logReply (code, requestStr, message);
|
||||
sendReply (
|
||||
code, false, "<h1>"+code+Code.msg(code)+"</h1>"+message
|
||||
);
|
||||
closeConnection(connection);
|
||||
}
|
||||
|
||||
void sendReply (
|
||||
int code, boolean closeNow, String text)
|
||||
{
|
||||
try {
|
||||
StringBuilder builder = new StringBuilder (512);
|
||||
builder.append ("HTTP/1.1 ")
|
||||
.append (code).append (Code.msg(code)).append ("\r\n");
|
||||
|
||||
if (text != null && text.length() != 0) {
|
||||
builder.append ("Content-Length: ")
|
||||
.append (text.length()).append ("\r\n")
|
||||
.append ("Content-Type: text/html\r\n");
|
||||
} else {
|
||||
builder.append ("Content-Length: 0\r\n");
|
||||
text = "";
|
||||
}
|
||||
if (closeNow) {
|
||||
builder.append ("Connection: close\r\n");
|
||||
}
|
||||
builder.append ("\r\n").append (text);
|
||||
String s = builder.toString();
|
||||
byte[] b = s.getBytes("ISO8859_1");
|
||||
rawout.write (b);
|
||||
rawout.flush();
|
||||
if (closeNow) {
|
||||
closeConnection(connection);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log (Level.TRACE, "ServerImpl.sendReply", e);
|
||||
closeConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void logReply (int code, String requestStr, String text) {
|
||||
if (!logger.isLoggable(Level.DEBUG)) {
|
||||
return;
|
||||
}
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
String r;
|
||||
if (requestStr.length() > 80) {
|
||||
r = requestStr.substring (0, 80) + "<TRUNCATED>";
|
||||
} else {
|
||||
r = requestStr;
|
||||
}
|
||||
String message = r + " [" + code + " " +
|
||||
Code.msg(code) + "] ("+text+")";
|
||||
logger.log (Level.DEBUG, message);
|
||||
}
|
||||
|
||||
long getTicks() {
|
||||
return ticks;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
void delay () {
|
||||
Thread.yield();
|
||||
try {
|
||||
Thread.sleep (200);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
|
||||
private int exchangeCount = 0;
|
||||
|
||||
synchronized void startExchange () {
|
||||
exchangeCount ++;
|
||||
}
|
||||
|
||||
synchronized int endExchange () {
|
||||
exchangeCount --;
|
||||
assert exchangeCount >= 0;
|
||||
return exchangeCount;
|
||||
}
|
||||
|
||||
HttpServer getWrapper () {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
void requestStarted (HttpConnection c) {
|
||||
c.creationTime = getTime();
|
||||
c.setState (State.REQUEST);
|
||||
reqConnections.add (c);
|
||||
}
|
||||
|
||||
// called after a request has been completely read
|
||||
// by the server. This stops the timer which would
|
||||
// close the connection if the request doesn't arrive
|
||||
// quickly enough. It then starts the timer
|
||||
// that ensures the client reads the response in a timely
|
||||
// fashion.
|
||||
|
||||
void requestCompleted (HttpConnection c) {
|
||||
assert c.getState() == State.REQUEST;
|
||||
reqConnections.remove (c);
|
||||
c.rspStartedTime = getTime();
|
||||
rspConnections.add (c);
|
||||
c.setState (State.RESPONSE);
|
||||
}
|
||||
|
||||
// called after response has been sent
|
||||
void responseCompleted (HttpConnection c) {
|
||||
assert c.getState() == State.RESPONSE;
|
||||
rspConnections.remove (c);
|
||||
c.setState (State.IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* TimerTask run every CLOCK_TICK ms
|
||||
*/
|
||||
class ServerTimerTask extends TimerTask {
|
||||
public void run () {
|
||||
LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>();
|
||||
time = System.currentTimeMillis();
|
||||
ticks ++;
|
||||
synchronized (idleConnections) {
|
||||
for (HttpConnection c : idleConnections) {
|
||||
if (c.time <= time) {
|
||||
toClose.add (c);
|
||||
}
|
||||
}
|
||||
for (HttpConnection c : toClose) {
|
||||
idleConnections.remove (c);
|
||||
allConnections.remove (c);
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ServerTimerTask1 extends TimerTask {
|
||||
|
||||
// runs every TIMER_MILLIS
|
||||
public void run () {
|
||||
LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>();
|
||||
time = System.currentTimeMillis();
|
||||
synchronized (reqConnections) {
|
||||
if (MAX_REQ_TIME != -1) {
|
||||
for (HttpConnection c : reqConnections) {
|
||||
if (c.creationTime + TIMER_MILLIS + MAX_REQ_TIME <= time) {
|
||||
toClose.add (c);
|
||||
}
|
||||
}
|
||||
for (HttpConnection c : toClose) {
|
||||
logger.log (Level.DEBUG, "closing: no request: " + c);
|
||||
reqConnections.remove (c);
|
||||
allConnections.remove (c);
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
toClose = new LinkedList<HttpConnection>();
|
||||
synchronized (rspConnections) {
|
||||
if (MAX_RSP_TIME != -1) {
|
||||
for (HttpConnection c : rspConnections) {
|
||||
if (c.rspStartedTime + TIMER_MILLIS +MAX_RSP_TIME <= time) {
|
||||
toClose.add (c);
|
||||
}
|
||||
}
|
||||
for (HttpConnection c : toClose) {
|
||||
logger.log (Level.DEBUG, "closing: no response: " + c);
|
||||
rspConnections.remove (c);
|
||||
allConnections.remove (c);
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void logStackTrace (String s) {
|
||||
logger.log (Level.TRACE, s);
|
||||
StringBuilder b = new StringBuilder ();
|
||||
StackTraceElement[] e = Thread.currentThread().getStackTrace();
|
||||
for (int i=0; i<e.length; i++) {
|
||||
b.append (e[i].toString()).append("\n");
|
||||
}
|
||||
logger.log (Level.TRACE, b.toString());
|
||||
}
|
||||
|
||||
static long getTimeMillis(long secs) {
|
||||
if (secs == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
return secs * 1000;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class StreamClosedException extends IOException {
|
||||
private static final long serialVersionUID = -4485921499356327937L;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
interface TimeSource {
|
||||
public long getTime();
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
import com.sun.net.httpserver.spi.*;
|
||||
|
||||
/**
|
||||
* a class which allows the caller to write an indefinite
|
||||
* number of bytes to an underlying stream , but without using
|
||||
* chunked encoding. Used for http/1.0 clients only
|
||||
* The underlying connection needs to be closed afterwards.
|
||||
*/
|
||||
|
||||
class UndefLengthOutputStream extends FilterOutputStream
|
||||
{
|
||||
private boolean closed = false;
|
||||
ExchangeImpl t;
|
||||
|
||||
UndefLengthOutputStream (ExchangeImpl t, OutputStream src) {
|
||||
super (src);
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public void write (int b) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("stream closed");
|
||||
}
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void write (byte[]b, int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException ("stream closed");
|
||||
}
|
||||
out.write(b, off, len);
|
||||
}
|
||||
|
||||
public void close () throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
flush();
|
||||
LeftOverInputStream is = t.getOriginalInputStream();
|
||||
if (!is.isClosed()) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
WriteFinishedEvent e = new WriteFinishedEvent (t);
|
||||
t.getHttpContext().getServerImpl().addEvent (e);
|
||||
}
|
||||
|
||||
// flush is a pass-through
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
import java.util.*;
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
class UnmodifiableHeaders extends Headers {
|
||||
|
||||
Headers map;
|
||||
|
||||
UnmodifiableHeaders(Headers map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public int size() {return map.size();}
|
||||
|
||||
public boolean isEmpty() {return map.isEmpty();}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey (key);
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
public List<String> get(Object key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public String getFirst (String key) {
|
||||
return map.getFirst(key);
|
||||
}
|
||||
|
||||
|
||||
public List<String> put(String key, List<String> value) {
|
||||
return map.put (key, value);
|
||||
}
|
||||
|
||||
public void add (String key, String value) {
|
||||
throw new UnsupportedOperationException ("unsupported operation");
|
||||
}
|
||||
|
||||
public void set (String key, String value) {
|
||||
throw new UnsupportedOperationException ("unsupported operation");
|
||||
}
|
||||
|
||||
public List<String> remove(Object key) {
|
||||
throw new UnsupportedOperationException ("unsupported operation");
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends String,? extends List<String>> t) {
|
||||
throw new UnsupportedOperationException ("unsupported operation");
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException ("unsupported operation");
|
||||
}
|
||||
|
||||
public Set<String> keySet() {
|
||||
return Collections.unmodifiableSet (map.keySet());
|
||||
}
|
||||
|
||||
public Collection<List<String>> values() {
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
|
||||
/* TODO check that contents of set are not modifable : security */
|
||||
|
||||
public Set<Map.Entry<String, List<String>>> entrySet() {
|
||||
return Collections.unmodifiableSet (map.entrySet());
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {return map.equals(o);}
|
||||
|
||||
public int hashCode() {return map.hashCode();}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver;
|
||||
|
||||
class WriteFinishedEvent extends Event {
|
||||
WriteFinishedEvent (ExchangeImpl t) {
|
||||
super (t);
|
||||
assert !t.writefinished;
|
||||
t.writefinished = true;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue