public void appendHead(Response res) throws IOException { if (log.isDebugEnabled()) log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders()); C2BConverter c2b = mc.getConverter(); outputMsg.reset(); outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS); outputMsg.appendInt(res.getStatus()); String message = null; if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER && HttpMessages.isSafeInHttpHeader(res.getMessage())) { message = res.getMessage(); } if (message == null) { message = HttpMessages.getMessage(res.getStatus()); } if (message == null) { // mod_jk + httpd 2.x fails with a null status message - bug 45026 message = Integer.toString(res.getStatus()); } tempMB.setString(message); c2b.convert(tempMB); outputMsg.appendBytes(tempMB); // XXX add headers MimeHeaders headers = res.getMimeHeaders(); String contentType = res.getContentType(); if (contentType != null) { headers.setValue("Content-Type").setString(contentType); } String contentLanguage = res.getContentLanguage(); if (contentLanguage != null) { headers.setValue("Content-Language").setString(contentLanguage); } long contentLength = res.getContentLengthLong(); if (contentLength >= 0) { headers.setValue("Content-Length").setLong(contentLength); } int numHeaders = headers.size(); outputMsg.appendInt(numHeaders); for (int i = 0; i < numHeaders; i++) { MessageBytes hN = headers.getName(i); // no header to sc conversion - there's little benefit // on this direction outputMsg.appendBytes(hN); MessageBytes hV = headers.getValue(i); outputMsg.appendBytes(hV); } mc.getSource().send(outputMsg, mc); }
// -------------------- Jk handler implementation -------------------- // Jk Handler mehod public int invoke(Msg msg, MsgContext ep) throws IOException { if (ep.isLogTimeEnabled()) ep.setLong(MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis()); Request req = ep.getRequest(); Response res = req.getResponse(); if (log.isDebugEnabled()) log.debug("Invoke " + req + " " + res + " " + req.requestURI().toString()); res.setNote(epNote, ep); ep.setStatus(MsgContext.JK_STATUS_HEAD); RequestInfo rp = req.getRequestProcessor(); rp.setStage(Constants.STAGE_SERVICE); try { adapter.service(req, res); } catch (Exception ex) { log.info("Error servicing request " + req, ex); } if (ep.getStatus() != MsgContext.JK_STATUS_CLOSED) { res.finish(); } req.updateCounters(); req.recycle(); res.recycle(); ep.recycle(); if (ep.getStatus() == MsgContext.JK_STATUS_ERROR) { return ERROR; } ep.setStatus(MsgContext.JK_STATUS_NEW); rp.setStage(Constants.STAGE_KEEPALIVE); return OK; }
/** * Get more request body data from the web server and store it in the internal buffer. * * @return true if there is more data, false if not. */ private boolean refillReadBuffer() throws IOException { // If the server returns an empty packet, assume that that end of // the stream has been reached (yuck -- fix protocol??). if (isReplay) { end_of_stream = true; // we've read everything there is } if (end_of_stream) { if (log.isDebugEnabled()) log.debug("refillReadBuffer: end of stream "); return false; } // Why not use outBuf?? bodyMsg.reset(); bodyMsg.appendByte(AjpConstants.JK_AJP13_GET_BODY_CHUNK); // Adjust allowed size if packetSize != default (AjpConstants.MAX_PACKET_SIZE) bodyMsg.appendInt(AjpConstants.MAX_READ_SIZE + packetSize - AjpConstants.MAX_PACKET_SIZE); if (log.isDebugEnabled()) log.debug("refillReadBuffer " + Thread.currentThread()); mc.getSource().send(bodyMsg, mc); mc.getSource().flush(bodyMsg, mc); // Server needs to get it // In JNI mode, response will be in bodyMsg. In TCP mode, response need to be // read boolean moreData = receive(); if (!moreData) { end_of_stream = true; } return moreData; }
/** * Receive a chunk of data. Called to implement the 'special' packet in ajp13 and to receive the * data after we send a GET_BODY packet */ public boolean receive() throws IOException { isFirst = false; bodyMsg.reset(); int err = mc.getSource().receive(bodyMsg, mc); if (log.isDebugEnabled()) log.info("Receiving: getting request body chunk " + err + " " + bodyMsg.getLen()); if (err < 0) { throw new IOException(); } // No data received. if (bodyMsg.getLen() == 0) { // just the header // Don't mark 'end of stream' for the first chunk. // end_of_stream = true; return false; } int blen = bodyMsg.peekInt(); if (blen == 0) { return false; } if (log.isTraceEnabled()) { bodyMsg.dump("Body buffer"); } bodyMsg.getBytes(bodyBuff); if (log.isTraceEnabled()) log.trace("Data:\n" + bodyBuff); isEmpty = false; return true; }
public int doWrite(ByteChunk chunk, Response res) throws IOException { if (!res.isCommitted()) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeader) and // set the filters accordingly. res.sendHeaders(); } int len = chunk.getLength(); byte buf[] = outputMsg.getBuffer(); // 4 - hardcoded, byte[] marshalling overhead int chunkSize = buf.length - outputMsg.getHeaderLength() - 4; int off = 0; while (len > 0) { int thisTime = len; if (thisTime > chunkSize) { thisTime = chunkSize; } len -= thisTime; outputMsg.reset(); outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_BODY_CHUNK); if (log.isTraceEnabled()) log.trace("doWrite " + off + " " + thisTime + " " + len); outputMsg.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime); off += thisTime; mc.getSource().send(outputMsg, mc); } return 0; }
public void endMessage() throws IOException { outputMsg.reset(); outputMsg.appendByte(AjpConstants.JK_AJP13_END_RESPONSE); outputMsg.appendByte(1); mc.getSource().send(outputMsg, mc); mc.getSource().flush(outputMsg, mc); }
public int invoke(Msg msg, MsgContext ep) throws IOException { int type = msg.peekByte(); ep.setType(type); if (type > handlers.length || handlers[type] == null) { if (log.isDebugEnabled()) log.debug("Invalid handler " + type); return ERROR; } if (log.isDebugEnabled()) log.debug("Received " + type + " " + handlers[type].getName()); JkHandler handler = handlers[type]; return handler.invoke(msg, ep); }