📄 serve.java
字号:
if ( lastDot == -1 ||
( lastSep != -1 && lastDot < lastSep ) )
return "text/plain; charset=iso-8859-1";
String extension = file.substring( lastDot + 1 );
if ( extension.equals( "html" ) || extension.equals( "htm" ) )
return "text/html; charset=iso-8859-1";
if ( extension.equals( "gif" ) )
return "image/gif";
if ( extension.equals( "jpg" ) || extension.equals( "jpeg" ) )
return "image/jpeg";
if ( extension.equals( "au" ) )
return "audio/basic";
if ( extension.equals( "ra" ) || extension.equals( "ram" ) )
return "audio/x-pn-realaudio";
if ( extension.equals( "wav" ) )
return "audio/wav";
if ( extension.equals( "mpg" ) || extension.equals( "mpeg" ) )
return "video/mpeg";
if ( extension.equals( "qt" ) || extension.equals( "mov" ) )
return "video/quicktime";
if ( extension.equals( "class" ) )
return "application/octet-stream";
if ( extension.equals( "ps" ) )
return "application/postscript";
if ( extension.equals( "wrl" ) )
return "x-world/x-vrml";
if ( extension.equals( "pac" ) )
return "application/x-ns-proxy-autoconfig";
return "text/plain; charset=iso-8859-1";
}
/// Returns the name and version of the web server under which the servlet
// is running.
// Same as the CGI variable SERVER_SOFTWARE.
public String getServerInfo()
{
return ServeUtils.serverName + " " + ServeUtils.serverVersion +
" (" + ServeUtils.serverUrl + ")";
}
/// Returns the value of the named attribute of the network service, or
// null if the attribute does not exist. This method allows access to
// additional information about the service, not already provided by
// the other methods in this interface.
public Object getAttribute( String name )
{
// This server does not support attributes.
return null;
}
}
class ServeConfig implements ServletConfig
{
private ServletContext context;
public ServeConfig( ServletContext context )
{
this.context = context;
}
// Methods from ServletConfig.
/// Returns the context for the servlet.
public ServletContext getServletContext()
{
return context;
}
/// Gets an initialization parameter of the servlet.
// @param name the parameter name
public String getInitParameter( String name )
{
// This server doesn't support servlet init params.
return null;
}
/// Gets the names of the initialization parameters of the servlet.
// @param name the parameter name
public Enumeration getInitParameterNames()
{
// This server doesn't support servlet init params.
return new Vector().elements();
}
}
class ServeConnection implements Runnable, HttpServletRequest, HttpServletResponse
{
private Socket socket;
private Serve serve;
private ServletInputStream in;
private ServletOutputStream out;
private Vector cookies = new Vector(); // !!!
/// Constructor.
public ServeConnection( Socket socket, Serve serve )
{
// Save arguments.
this.socket = socket;
this.serve = serve;
// Start a separate thread to read and handle the request.
Thread thread = new Thread( this );
thread.start();
}
// Methods from Runnable.
private String reqMethod = null;
private String reqUriPath = null;
private String reqProtocol = null;
private boolean oneOne; // HTTP/1.1 or better
private boolean reqMime;
String reqQuery = null;
private Vector reqHeaderNames = new Vector();
private Vector reqHeaderValues = new Vector();
public void run()
{
try
{
// Get the streams.
in = new ServeInputStream( socket.getInputStream() );
out = new ServeOutputStream( socket.getOutputStream(), this );
}
catch ( IOException e )
{
problem( "Getting streams: " + e.getMessage(), SC_BAD_REQUEST );
}
parseRequest();
try
{
socket.close();
}
catch ( IOException e ) { /* ignore */ }
}
private void parseRequest()
{
byte[] lineBytes = new byte[4096];
int len;
String line;
try
{
// Read the first line of the request.
len = in.readLine( lineBytes, 0, lineBytes.length );
if ( len == -1 || len == 0 )
{
problem( "Empty request", SC_BAD_REQUEST );
return;
}
line = new String( lineBytes, 0, len );
String[] tokens = Acme.Utils.splitStr( line );
switch ( tokens.length )
{
case 2:
// Two tokens means the protocol is HTTP/0.9.
reqProtocol = "HTTP/0.9";
oneOne = false;
reqMime = false;
break;
case 3:
reqProtocol = tokens[2];
oneOne = ! reqProtocol.toUpperCase().equals( "HTTP/1.0" );
reqMime = true;
// Read the rest of the lines.
while ( true )
{
len = in.readLine( lineBytes, 0, lineBytes.length );
if ( len == -1 || len == 0 )
break;
line = new String( lineBytes, 0, len );
int colonBlank = line.indexOf( ": " );
if ( colonBlank != -1 )
{
String name = line.substring( 0, colonBlank );
String value = line.substring( colonBlank + 2 );
reqHeaderNames.addElement( name.toLowerCase() );
reqHeaderValues.addElement( value );
}
}
break;
default:
problem( "Malformed request line", SC_BAD_REQUEST );
return;
}
reqMethod = tokens[0];
reqUriPath = tokens[1];
// Check Host: header in HTTP/1.1 requests.
if ( oneOne )
{
String host = getHeader( "host" );
if ( host == null )
{
problem(
"Host header missing on HTTP/1.1 request",
SC_BAD_REQUEST );
return;
}
// !!!
}
// Split off query string, if any.
int qmark = reqUriPath.indexOf( '?' );
if ( qmark != -1 )
{
reqQuery = reqUriPath.substring( qmark + 1 );
reqUriPath = reqUriPath.substring( 0, qmark );
}
// Decode %-sequences.
reqUriPath = decode( reqUriPath );
Servlet servlet = (Servlet) serve.registry.get( reqUriPath );
if ( servlet != null )
runServlet( (HttpServlet) servlet );
}
catch ( IOException e )
{
problem( "Reading request: " + e.getMessage(), SC_BAD_REQUEST );
}
}
private void runServlet( HttpServlet servlet )
{
// Set default response fields.
setStatus( SC_OK );
setDateHeader( "Date", System.currentTimeMillis() );
setHeader(
"Server", ServeUtils.serverName + "/" + ServeUtils.serverVersion );
setHeader( "Connection", "close" );
try
{
servlet.service( this, this );
}
catch ( IOException e )
{
problem(
"IO problem running servlet: " + e.toString(), SC_BAD_REQUEST );
}
catch ( ServletException e )
{
problem(
"problem running servlet: " + e.toString(), SC_BAD_REQUEST );
}
catch ( Exception e )
{
problem(
"unexpected problem running servlet: " + e.toString(),
SC_INTERNAL_SERVER_ERROR );
}
}
private void problem( String logMessage, int resCode )
{
serve.log( logMessage );
try
{
sendError( resCode );
}
catch ( IOException e ) { /* ignore */ }
}
private String decode( String str )
{
StringBuffer result = new StringBuffer();
int l = str.length();
for ( int i = 0; i < l; ++i )
{
char c = str.charAt( i );
if ( c == '%' && i + 2 < l )
{
char c1 = str.charAt( i + 1 );
char c2 = str.charAt( i + 2 );
if ( isHexit( c1 ) && isHexit( c2 ) )
{
result.append( (char) ( hexit( c1 ) * 16 + hexit( c2 ) ) );
i += 2;
}
else
result.append( c );
}
else
result.append( c );
}
return result.toString();
}
private boolean isHexit( char c )
{
String legalChars = "0123456789abcdefABCDEF";
return ( legalChars.indexOf( c ) != -1 );
}
private int hexit( char c )
{
if ( c >= '0' && c <= '9' )
return c - '0';
if ( c >= 'a' && c <= 'f' )
return c - 'a' + 10;
if ( c >= 'A' && c <= 'F' )
return c - 'A' + 10;
return 0; // shouldn't happen, we're guarded by isHexit()
}
// Methods from ServletRequest.
/// Returns the size of the request entity data, or -1 if not known.
// Same as the CGI variable CONTENT_LENGTH.
public int getContentLength()
{
return getIntHeader( "content-length", -1 );
}
/// Returns the MIME type of the request entity data, or null if
// not known.
// Same as the CGI variable CONTENT_TYPE.
public String getContentType()
{
return getHeader( "content-type" );
}
/// Returns the protocol and version of the request as a string of
// the form <protocol>/<major version>.<minor version>.
// Same as the CGI variable SERVER_PROTOCOL.
public String getProtocol()
{
return reqProtocol;
}
/// Returns the scheme of the URL used in this request, for example
// "http", "https", or "ftp". Different schemes have different rules
// for constructing URLs, as noted in RFC 1738. The URL used to create
// a request may be reconstructed using this scheme, the server name
// and port, and additional information such as URIs.
public String getScheme()
{
return "http";
}
/// Returns the host name of the server as used in the <host> part of
// the request URI.
// Same as the CGI variable SERVER_NAME.
public String getServerName()
{
try
{
return InetAddress.getLocalHost().getHostName();
}
catch ( UnknownHostException e )
{
return null;
}
}
/// Returns the port number on which this request was received as used in
// the <port> part of the request URI.
// Same as the CGI variable SERVER_PORT.
public int getServerPort()
{
return socket.getLocalPort();
}
/// Returns the IP address of the agent that sent the request.
// Same as the CGI variable REMOTE_ADDR.
public String getRemoteAddr()
{
return socket.getInetAddress().toString();
}
/// Returns the fully qualified host name of the agent that sent the
// request.
// Same as the CGI variable REMOTE_HOST.
public String getRemoteHost()
{
return socket.getInetAddress().getHostName();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -