Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.grizzly.http.jk.common;
import com.sun.grizzly.http.jk.core.JkChannel;
import com.sun.grizzly.http.jk.core.JkHandler;
import com.sun.grizzly.http.jk.core.Msg;
import com.sun.grizzly.http.jk.core.MsgContext;
import com.sun.grizzly.http.jk.core.WorkerEnv;
import com.sun.grizzly.http.jk.util.threads.ThreadWithAttributes;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.CharConversionException;
import java.net.InetAddress;
import java.util.Properties;
import com.sun.grizzly.tcp.Request;
import com.sun.grizzly.tcp.RequestInfo;
import com.sun.grizzly.tcp.Response;
import com.sun.grizzly.tcp.Constants;
import com.sun.grizzly.util.LoggerUtils;
import com.sun.grizzly.util.buf.ByteChunk;
import com.sun.grizzly.util.buf.CharChunk;
import com.sun.grizzly.util.buf.HexUtils;
import com.sun.grizzly.util.buf.MessageBytes;
import com.sun.grizzly.util.http.MimeHeaders;
import com.sun.grizzly.util.net.SSLSupport;
import java.util.logging.Level;
/**
* Handle messages related with basic request information.
*
* This object can handle the following incoming messages:
* - "FORWARD_REQUEST" input message ( sent when a request is passed from the
* web server )
* - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in
* response to GET_BODY_CHUNK )
*
* It can handle the following outgoing messages:
* - SEND_HEADERS. Pass the status code and headers.
* - SEND_BODY_CHUNK. Send a chunk of body
* - GET_BODY_CHUNK. Request a chunk of body data
* - END_RESPONSE. Notify the end of a request processing.
*
* @author Henri Gomez [[email protected]]
* @author Dan Milstein [[email protected]]
* @author Keith Wannamaker [[email protected]]
* @author Costin Manolache
*/
public class HandlerRequest extends JkHandler {
/*
* Note for Host parsing.
*/
public static final int HOSTBUFFER = 10;
/**
* Thread lock.
*/
private static Object lock = new Object();
private HandlerDispatch dispatch;
private String ajpidDir = "conf";
public HandlerRequest() {
}
public void init() {
dispatch = (HandlerDispatch) wEnv.getHandler("dispatch");
if (dispatch != null) {
// register incoming message handlers
dispatch.registerMessageType(AjpConstants.JK_AJP13_FORWARD_REQUEST,
"JK_AJP13_FORWARD_REQUEST",
this, null); // 2
dispatch.registerMessageType(AjpConstants.JK_AJP13_SHUTDOWN,
"JK_AJP13_SHUTDOWN",
this, null); // 7
dispatch.registerMessageType(AjpConstants.JK_AJP13_CPING_REQUEST,
"JK_AJP13_CPING_REQUEST",
this, null); // 10
dispatch.registerMessageType(HANDLE_THREAD_END,
"HANDLE_THREAD_END",
this, null);
// register outgoing messages handler
dispatch.registerMessageType(AjpConstants.JK_AJP13_SEND_BODY_CHUNK, // 3
"JK_AJP13_SEND_BODY_CHUNK",
this, null);
}
tmpBufNote = wEnv.getNoteId(WorkerEnv.ENDPOINT_NOTE, "tmpBuf");
secretNote = wEnv.getNoteId(WorkerEnv.ENDPOINT_NOTE, "secret");
if (next == null) {
next = wEnv.getHandler("container");
}
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Container handler " + next + " " + next.getName() +
" " + next.getClass().getName());
}
// should happen on start()
generateAjp13Id();
}
public void setSecret(String s) {
requiredSecret = s;
}
public void setUseSecret(boolean b) {
if (b) {
requiredSecret = Double.toString(Math.random());
}
}
public void setDecodedUri(boolean b) {
decoded = b;
}
public boolean isTomcatAuthentication() {
return tomcatAuthentication;
}
public void setShutdownEnabled(boolean se) {
shutdownEnabled = se;
}
public boolean getShutdownEnabled() {
return shutdownEnabled;
}
public void setTomcatAuthentication(boolean newTomcatAuthentication) {
tomcatAuthentication = newTomcatAuthentication;
}
public void setAjpidDir(String path) {
if ("".equals(path)) {
path = null;
}
ajpidDir = path;
}
/**
* Set the flag to tell if we JMX register requests.
*/
public void setRegisterRequests(boolean srr) {
registerRequests = srr;
}
/**
* Get the flag to tell if we JMX register requests.
*/
public boolean getRegisterRequests() {
return registerRequests;
}
/**
* Set the flag to delay the initial body read
*/
public void setDelayInitialRead(boolean dir) {
delayInitialRead = dir;
}
/**
* Get the flag to tell if we delay the initial body read
*/
public boolean getDelayInitialRead() {
return delayInitialRead;
}
// -------------------- Ajp13.id --------------------
private void generateAjp13Id() {
int portInt = 8009; // tcpCon.getPort();
InetAddress address = null; // tcpCon.getAddress();
if (requiredSecret == null || !shutdownEnabled) {
return;
}
File f1 = new File(wEnv.getJkHome());
File f2 = new File(f1, "conf");
if (!f2.exists()) {
LoggerUtils.getLogger().log(Level.SEVERE, "No conf dir for ajp13.id " + f2);
return;
}
File sf = new File(f2, "ajp13.id");
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Using stop file: " + sf);
}
try {
Properties props = new Properties();
props.put("port", Integer.toString(portInt));
if (address != null) {
props.put("address", address.getHostAddress());
}
if (requiredSecret != null) {
props.put("secret", requiredSecret);
}
FileOutputStream stopF = new FileOutputStream(sf);
props.store(stopF, "Automatically generated, don't edit");
} catch (IOException ex) {
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Can't create stop file: " + sf, ex);
}
}
}
// -------------------- Incoming message --------------------
private String requiredSecret = null;
private int secretNote;
private int tmpBufNote;
private boolean decoded = true;
private boolean tomcatAuthentication = true;
private boolean registerRequests = true;
private boolean shutdownEnabled = false;
private boolean delayInitialRead = true;
public int invoke(Msg msg, MsgContext ep)
throws IOException {
int type = msg.getByte();
ThreadWithAttributes twa = null;
if (Thread.currentThread() instanceof ThreadWithAttributes) {
twa = (ThreadWithAttributes) Thread.currentThread();
}
Object control = ep.getControl();
MessageBytes tmpMB = (MessageBytes) ep.getNote(tmpBufNote);
if (tmpMB == null) {
tmpMB = MessageBytes.newInstance();
ep.setNote(tmpBufNote, tmpMB);
}
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Handling " + type);
}
switch (type) {
case AjpConstants.JK_AJP13_FORWARD_REQUEST:
try {
if (twa != null) {
twa.setCurrentStage(control, "JkDecode");
}
decodeRequest(msg, ep, tmpMB);
if (twa != null) {
twa.setCurrentStage(control, "JkService");
twa.setParam(control,
((Request) ep.getRequest()).unparsedURI());
}
} catch (Exception ex) {
/* If we are here it is because we have a bad header or something like that */
LoggerUtils.getLogger().log(Level.SEVERE, "Error decoding request ", ex);
msg.dump("Incomming message");
Response res = ep.getRequest().getResponse();
if (res == null) {
res = new Response();
ep.getRequest().setResponse(res);
}
res.setMessage("Bad Request");
res.setStatus(400);
return ERROR;
}
if (requiredSecret != null) {
String epSecret = (String) ep.getNote(secretNote);
if (epSecret == null || !requiredSecret.equals(epSecret)) {
return ERROR;
}
}
/* XXX it should be computed from request, by workerEnv */
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Calling next " + next.getName() + " " +
next.getClass().getName());
}
int err = next.invoke(msg, ep);
if (twa != null) {
twa.setCurrentStage(control, "JkDone");
}
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Invoke returned " + err);
}
return err;
case AjpConstants.JK_AJP13_SHUTDOWN:
String epSecret = null;
if (msg.getLen() > 3) {
// we have a secret
msg.getBytes(tmpMB);
epSecret = tmpMB.toString();
}
if (requiredSecret != null &&
requiredSecret.equals(epSecret)) {
if (LoggerUtils.getLogger().isLoggable(Level.FINEST)) {
LoggerUtils.getLogger().log(Level.FINEST, "Received wrong secret, no shutdown ");
}
return ERROR;
}
// XXX add isSameAddress check
JkChannel ch = ep.getSource();
if (!ch.isSameAddress(ep)) {
LoggerUtils.getLogger().log(Level.SEVERE, "Shutdown request not from 'same address' ");
return ERROR;
}
if (!shutdownEnabled) {
LoggerUtils.getLogger().log(Level.WARNING, "Ignoring shutdown request: shutdown not enabled");
return ERROR;
}
// forward to the default handler - it'll do the shutdown
checkRequest(ep);
next.invoke(msg, ep);
LoggerUtils.getLogger().info("Exiting");
System.exit(0);
return OK;
// We got a PING REQUEST, quickly respond with a PONG
case AjpConstants.JK_AJP13_CPING_REQUEST:
msg.reset();
msg.appendByte(AjpConstants.JK_AJP13_CPONG_REPLY);
ep.getSource().send(msg, ep);
ep.getSource().flush(msg, ep); // Server needs to get it
return OK;
case HANDLE_THREAD_END:
return OK;
default:
LoggerUtils.getLogger().info("Unknown message " + type);
}
return OK;
}
static int count = 0;
private Request checkRequest(MsgContext ep) {
Request req = ep.getRequest();
if (req == null) {
req = new Request();
Response res = new Response();
req.setResponse(res);
ep.setRequest(req);
if (registerRequests) {
synchronized (lock) {
ep.getSource().registerRequest(req, ep, count++);
}
}
}
return req;
}
private int decodeRequest(Msg msg, MsgContext ep, MessageBytes tmpMB)
throws IOException {
// FORWARD_REQUEST handler
Request req = checkRequest(ep);
RequestInfo rp = req.getRequestProcessor();
rp.setStage(Constants.STAGE_PARSE);
MessageBytes tmpMB2 = (MessageBytes) req.getNote(WorkerEnv.SSL_CERT_NOTE);
if (tmpMB2 != null) {
tmpMB2.recycle();
}
req.setStartTime(System.currentTimeMillis());
// Translate the HTTP method code to a String.
byte methodCode = msg.getByte();
if (methodCode != AjpConstants.SC_M_JK_STORED) {
String mName = AjpConstants.methodTransArray[(int) methodCode - 1];
req.method().setString(mName);
}
msg.getBytes(req.protocol());
msg.getBytes(req.requestURI());
msg.getBytes(req.remoteAddr());
msg.getBytes(req.remoteHost());
msg.getBytes(req.localName());
req.setLocalPort(msg.getInt());
boolean isSSL = msg.getByte() != 0;
if (isSSL) {
// XXX req.setSecure( true );
req.scheme().setString("https");
}
decodeHeaders(ep, msg, req, tmpMB);
decodeAttributes(ep, msg, req, tmpMB);
rp.setStage(Constants.STAGE_PREPARE);
MessageBytes valueMB = req.getMimeHeaders().getValue("host");
parseHost(valueMB, req);
// set cookies on request now that we have all headers
req.getCookies().setHeaders(req.getMimeHeaders());
// Check to see if there should be a body packet coming along
// immediately after
long cl = req.getContentLengthLong();
if (cl > 0) {
JkInputStream jkIS = ep.getInputStream();
jkIS.setIsReadRequired(true);
if (!delayInitialRead) {
jkIS.receive();
}
}
return OK;
}
private int decodeAttributes( MsgContext ep, Msg msg, Request req,
MessageBytes tmpMB) {
boolean moreAttr=true;
while (moreAttr) {
byte attributeCode = msg.getByte();
if (attributeCode == AjpConstants.SC_A_ARE_DONE) {
return 200;
}
/* Special case ( XXX in future API make it separate type !)
*/
if (attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE) {
// Bug 1326: it's an Integer.
req.setAttribute(SSLSupport.KEY_SIZE_KEY,
new Integer(msg.getInt()));
//Integer.toString(msg.getInt()));
}
if (attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE) {
// 2 strings ???...
msg.getBytes(tmpMB);
String n = tmpMB.toString();
msg.getBytes(tmpMB);
String v = tmpMB.toString();
req.setAttribute(n, v);
}
// 1 string attributes
switch (attributeCode) {
case AjpConstants.SC_A_CONTEXT:
msg.getBytes(tmpMB);
// nothing
break;
case AjpConstants.SC_A_SERVLET_PATH:
msg.getBytes(tmpMB);
// nothing
break;
case AjpConstants.SC_A_REMOTE_USER:
if (tomcatAuthentication) {
// ignore server
msg.getBytes(tmpMB);
} else {
msg.getBytes(req.getRemoteUser());
}
break;
case AjpConstants.SC_A_AUTH_TYPE:
if (tomcatAuthentication) {
// ignore server
msg.getBytes(tmpMB);
} else {
msg.getBytes(req.getAuthType());
}
break;
case AjpConstants.SC_A_QUERY_STRING:
msg.getBytes(req.queryString());
break;
case AjpConstants.SC_A_JVM_ROUTE:
msg.getBytes(req.instanceId());
break;
case AjpConstants.SC_A_SSL_CERT:
req.scheme().setString("https");
// Transform the string into certificate.
MessageBytes tmpMB2 = (MessageBytes) req.getNote(WorkerEnv.SSL_CERT_NOTE);
if (tmpMB2 == null) {
tmpMB2 = MessageBytes.newInstance();
req.setNote(WorkerEnv.SSL_CERT_NOTE, tmpMB2);
}
// SSL certificate extraction is costy, moved to JkCoyoteHandler
msg.getBytes(tmpMB2);
break;
case AjpConstants.SC_A_SSL_CIPHER:
req.scheme().setString("https");
msg.getBytes(tmpMB);
req.setAttribute(SSLSupport.CIPHER_SUITE_KEY,
tmpMB.toString());
break;
case AjpConstants.SC_A_SSL_SESSION:
req.scheme().setString("https");
msg.getBytes(tmpMB);
req.setAttribute(SSLSupport.SESSION_ID_KEY,
tmpMB.toString());
break;
case AjpConstants.SC_A_SECRET:
msg.getBytes(tmpMB);
String secret = tmpMB.toString();
// endpoint note
ep.setNote(secretNote, secret);
break;
case AjpConstants.SC_A_STORED_METHOD:
msg.getBytes(req.method());
break;
default:
break; // ignore, we don't know about it - backward compat
}
}
return 200;
}
private void decodeHeaders(MsgContext ep, Msg msg, Request req,
MessageBytes tmpMB) {
// Decode headers
MimeHeaders headers = req.getMimeHeaders();
int hCount = msg.getInt();
for (int i = 0; i < hCount; i++) {
String hName = null;
// Header names are encoded as either an integer code starting
// with 0xA0, or as a normal string (in which case the first
// two bytes are the length).
int isc = msg.peekInt();
int hId = isc & 0xFF;
MessageBytes vMB = null;
isc &= 0xFF00;
if (0xA000 == isc) {
msg.getInt(); // To advance the read position
hName = AjpConstants.headerTransArray[hId - 1];
vMB = headers.addValue(hName);
} else {
// reset hId -- if the header currently being read
// happens to be 7 or 8 bytes long, the code below
// will think it's the content-type header or the
// content-length header - SC_REQ_CONTENT_TYPE=7,
// SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
// behaviour. see bug 5861 for more information.
hId = -1;
msg.getBytes(tmpMB);
ByteChunk bc = tmpMB.getByteChunk();
vMB = headers.addValue(bc.getBuffer(),
bc.getStart(), bc.getLength());
}
msg.getBytes(vMB);
if (hId == AjpConstants.SC_REQ_CONTENT_LENGTH ||
(hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
// just read the content-length header, so set it
long cl = vMB.getLong();
if (cl < Integer.MAX_VALUE) {
req.setContentLength((int) cl);
}
} else if (hId == AjpConstants.SC_REQ_CONTENT_TYPE ||
(hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
// just read the content-type header, so set it
ByteChunk bchunk = vMB.getByteChunk();
req.contentType().setBytes(bchunk.getBytes(),
bchunk.getOffset(),
bchunk.getLength());
}
}
}
/**
* Parse host.
*/
private void parseHost(MessageBytes valueMB, Request request)
throws IOException {
if (valueMB == null || valueMB.isNull()) {
// HTTP/1.0
// Default is what the socket tells us. Overriden if a host is
// found/parsed
request.setServerPort(request.getLocalPort());
request.serverName().duplicate(request.localName());
return;
}
ByteChunk valueBC = valueMB.getByteChunk();
byte[] valueB = valueBC.getBytes();
int valueL = valueBC.getLength();
int valueS = valueBC.getStart();
int colonPos = -1;
CharChunk hostNameC = (CharChunk) request.getNote(HOSTBUFFER);
if (hostNameC == null) {
hostNameC = new CharChunk(valueL);
request.setNote(HOSTBUFFER, hostNameC);
}
hostNameC.recycle();
boolean ipv6 = (valueB[valueS] == '[');
boolean bracketClosed = false;
for (int i = 0; i < valueL; i++) {
char b = (char) valueB[i + valueS];
hostNameC.append(b);
if (b == ']') {
bracketClosed = true;
} else if (b == ':') {
if (!ipv6 || bracketClosed) {
colonPos = i;
break;
}
}
}
if (colonPos < 0) {
if (request.scheme().equalsIgnoreCase("https")) {
// 80 - Default HTTTP port
request.setServerPort(443);
} else {
// 443 - Default HTTPS port
request.setServerPort(80);
}
request.serverName().setChars(hostNameC.getChars(),
hostNameC.getStart(),
hostNameC.getLength());
} else {
request.serverName().setChars(hostNameC.getChars(),
hostNameC.getStart(), colonPos);
int port = 0;
int mult = 1;
for (int i = valueL - 1; i > colonPos; i--) {
int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
if (charValue == -1) {
// Invalid character
throw new CharConversionException("Invalid char in port: " + valueB[i + valueS]);
}
port = port + (charValue * mult);
mult = 10 * mult;
}
request.setServerPort(port);
}
}
}