PageRenderTime 64ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/tomcat-7.0.2/java/org/apache/coyote/ajp/AjpProcessor.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1367 lines | 785 code | 259 blank | 323 comment | 179 complexity | 1759c6fc628fc3f749e7b6d754dc8901 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.coyote.ajp;
  18. import java.io.ByteArrayInputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InterruptedIOException;
  22. import java.io.OutputStream;
  23. import java.net.InetAddress;
  24. import java.net.Socket;
  25. import java.security.cert.CertificateFactory;
  26. import java.security.cert.X509Certificate;
  27. import java.util.concurrent.atomic.AtomicBoolean;
  28. import org.apache.coyote.ActionCode;
  29. import org.apache.coyote.ActionHook;
  30. import org.apache.coyote.Adapter;
  31. import org.apache.coyote.InputBuffer;
  32. import org.apache.coyote.OutputBuffer;
  33. import org.apache.coyote.Request;
  34. import org.apache.coyote.RequestInfo;
  35. import org.apache.coyote.Response;
  36. import org.apache.juli.logging.Log;
  37. import org.apache.juli.logging.LogFactory;
  38. import org.apache.tomcat.util.buf.ByteChunk;
  39. import org.apache.tomcat.util.buf.HexUtils;
  40. import org.apache.tomcat.util.buf.MessageBytes;
  41. import org.apache.tomcat.util.http.HttpMessages;
  42. import org.apache.tomcat.util.http.MimeHeaders;
  43. import org.apache.tomcat.util.net.AbstractEndpoint;
  44. import org.apache.tomcat.util.net.JIoEndpoint;
  45. import org.apache.tomcat.util.net.SocketStatus;
  46. import org.apache.tomcat.util.net.SocketWrapper;
  47. import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
  48. import org.apache.tomcat.util.res.StringManager;
  49. /**
  50. * Processes HTTP requests.
  51. *
  52. * @author Remy Maucherat
  53. * @author Henri Gomez
  54. * @author Dan Milstein
  55. * @author Keith Wannamaker
  56. * @author Kevin Seguin
  57. * @author Costin Manolache
  58. * @author Bill Barker
  59. */
  60. public class AjpProcessor implements ActionHook {
  61. /**
  62. * Logger.
  63. */
  64. private static final Log log = LogFactory.getLog(AjpProcessor.class);
  65. /**
  66. * The string manager for this package.
  67. */
  68. protected static final StringManager sm =
  69. StringManager.getManager(Constants.Package);
  70. // ----------------------------------------------------------- Constructors
  71. public AjpProcessor(int packetSize, JIoEndpoint endpoint) {
  72. this.endpoint = endpoint;
  73. request = new Request();
  74. request.setInputBuffer(new SocketInputBuffer());
  75. response = new Response();
  76. response.setHook(this);
  77. response.setOutputBuffer(new SocketOutputBuffer());
  78. request.setResponse(response);
  79. this.packetSize = packetSize;
  80. requestHeaderMessage = new AjpMessage(packetSize);
  81. responseHeaderMessage = new AjpMessage(packetSize);
  82. bodyMessage = new AjpMessage(packetSize);
  83. // Set the get body message buffer
  84. AjpMessage getBodyMessage = new AjpMessage(16);
  85. getBodyMessage.reset();
  86. getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
  87. // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE)
  88. getBodyMessage.appendInt(Constants.MAX_READ_SIZE + packetSize - Constants.MAX_PACKET_SIZE);
  89. getBodyMessage.end();
  90. getBodyMessageArray = new byte[getBodyMessage.getLen()];
  91. System.arraycopy(getBodyMessage.getBuffer(), 0, getBodyMessageArray,
  92. 0, getBodyMessage.getLen());
  93. // Cause loading of HexUtils
  94. HexUtils.load();
  95. // Cause loading of HttpMessages
  96. HttpMessages.getMessage(200);
  97. }
  98. // ----------------------------------------------------- Instance Variables
  99. /**
  100. * Associated adapter.
  101. */
  102. protected Adapter adapter = null;
  103. /**
  104. * Request object.
  105. */
  106. protected Request request = null;
  107. /**
  108. * Response object.
  109. */
  110. protected Response response = null;
  111. /**
  112. * The socket timeout used when reading the first block of the request
  113. * header.
  114. */
  115. protected int packetSize;
  116. /**
  117. * Header message. Note that this header is merely the one used during the
  118. * processing of the first message of a "request", so it might not be a request
  119. * header. It will stay unchanged during the processing of the whole request.
  120. */
  121. protected AjpMessage requestHeaderMessage = null;
  122. /**
  123. * Message used for response header composition.
  124. */
  125. protected AjpMessage responseHeaderMessage = null;
  126. /**
  127. * Body message.
  128. */
  129. protected AjpMessage bodyMessage = null;
  130. /**
  131. * Body message.
  132. */
  133. protected MessageBytes bodyBytes = MessageBytes.newInstance();
  134. /**
  135. * State flag.
  136. */
  137. protected boolean started = false;
  138. /**
  139. * Error flag.
  140. */
  141. protected boolean error = false;
  142. /**
  143. * Socket associated with the current connection.
  144. */
  145. protected SocketWrapper<Socket> socket;
  146. /**
  147. * Input stream.
  148. */
  149. protected InputStream input;
  150. /**
  151. * Output stream.
  152. */
  153. protected OutputStream output;
  154. /**
  155. * Host name (used to avoid useless B2C conversion on the host name).
  156. */
  157. protected char[] hostNameC = new char[0];
  158. /**
  159. * Associated endpoint.
  160. */
  161. protected JIoEndpoint endpoint;
  162. /**
  163. * Temp message bytes used for processing.
  164. */
  165. protected MessageBytes tmpMB = MessageBytes.newInstance();
  166. /**
  167. * Byte chunk for certs.
  168. */
  169. protected MessageBytes certificates = MessageBytes.newInstance();
  170. /**
  171. * End of stream flag.
  172. */
  173. protected boolean endOfStream = false;
  174. /**
  175. * Body empty flag.
  176. */
  177. protected boolean empty = true;
  178. /**
  179. * First read.
  180. */
  181. protected boolean first = true;
  182. /**
  183. * Replay read.
  184. */
  185. protected boolean replay = false;
  186. /**
  187. * Finished response.
  188. */
  189. protected boolean finished = false;
  190. /**
  191. * Direct buffer used for sending right away a get body message.
  192. */
  193. protected final byte[] getBodyMessageArray;
  194. /**
  195. * Direct buffer used for sending right away a pong message.
  196. */
  197. protected static final byte[] pongMessageArray;
  198. /**
  199. * End message array.
  200. */
  201. protected static final byte[] endMessageArray;
  202. /**
  203. * Flush message array.
  204. */
  205. protected static final byte[] flushMessageArray;
  206. /**
  207. * Async used
  208. */
  209. protected boolean async = false;
  210. // ----------------------------------------------------- Static Initializer
  211. static {
  212. // Set the read body message buffer
  213. AjpMessage pongMessage = new AjpMessage(16);
  214. pongMessage.reset();
  215. pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
  216. pongMessage.end();
  217. pongMessageArray = new byte[pongMessage.getLen()];
  218. System.arraycopy(pongMessage.getBuffer(), 0, pongMessageArray,
  219. 0, pongMessage.getLen());
  220. // Allocate the end message array
  221. AjpMessage endMessage = new AjpMessage(16);
  222. endMessage.reset();
  223. endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
  224. endMessage.appendByte(1);
  225. endMessage.end();
  226. endMessageArray = new byte[endMessage.getLen()];
  227. System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
  228. endMessage.getLen());
  229. // Allocate the flush message array
  230. AjpMessage flushMessage = new AjpMessage(16);
  231. flushMessage.reset();
  232. flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
  233. flushMessage.appendInt(0);
  234. flushMessage.appendByte(0);
  235. flushMessage.end();
  236. flushMessageArray = new byte[flushMessage.getLen()];
  237. System.arraycopy(flushMessage.getBuffer(), 0, flushMessageArray, 0,
  238. flushMessage.getLen());
  239. }
  240. // ------------------------------------------------------------- Properties
  241. /**
  242. * Use Tomcat authentication ?
  243. */
  244. protected boolean tomcatAuthentication = true;
  245. public boolean getTomcatAuthentication() { return tomcatAuthentication; }
  246. public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
  247. /**
  248. * Required secret.
  249. */
  250. protected String requiredSecret = null;
  251. public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; }
  252. /**
  253. * The number of milliseconds Tomcat will wait for a subsequent request
  254. * before closing the connection. The default is the same as for
  255. * Apache HTTP Server (15 000 milliseconds).
  256. */
  257. protected int keepAliveTimeout = -1;
  258. public int getKeepAliveTimeout() { return keepAliveTimeout; }
  259. public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout; }
  260. // --------------------------------------------------------- Public Methods
  261. /** Get the request associated with this processor.
  262. *
  263. * @return The request
  264. */
  265. public Request getRequest() {
  266. return request;
  267. }
  268. /**
  269. * Process pipelined HTTP requests using the specified input and output
  270. * streams.
  271. *
  272. * @throws IOException error during an I/O operation
  273. */
  274. public SocketState process(SocketWrapper<Socket> socket)
  275. throws IOException {
  276. RequestInfo rp = request.getRequestProcessor();
  277. rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
  278. // Setting up the socket
  279. this.socket = socket;
  280. input = socket.getSocket().getInputStream();
  281. output = socket.getSocket().getOutputStream();
  282. int soTimeout = -1;
  283. if (keepAliveTimeout > 0) {
  284. soTimeout = socket.getSocket().getSoTimeout();
  285. }
  286. // Error flag
  287. error = false;
  288. while (started && !error) {
  289. // Parsing the request header
  290. try {
  291. // Set keep alive timeout if enabled
  292. if (keepAliveTimeout > 0) {
  293. socket.getSocket().setSoTimeout(keepAliveTimeout);
  294. }
  295. // Get first message of the request
  296. if (!readMessage(requestHeaderMessage)) {
  297. // This means a connection timeout
  298. rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  299. break;
  300. }
  301. // Set back timeout if keep alive timeout is enabled
  302. if (keepAliveTimeout > 0) {
  303. socket.getSocket().setSoTimeout(soTimeout);
  304. }
  305. // Check message type, process right away and break if
  306. // not regular request processing
  307. int type = requestHeaderMessage.getByte();
  308. if (type == Constants.JK_AJP13_CPING_REQUEST) {
  309. try {
  310. output.write(pongMessageArray);
  311. } catch (IOException e) {
  312. error = true;
  313. }
  314. continue;
  315. } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) {
  316. // Usually the servlet didn't read the previous request body
  317. if(log.isDebugEnabled()) {
  318. log.debug("Unexpected message: "+type);
  319. }
  320. continue;
  321. }
  322. request.setStartTime(System.currentTimeMillis());
  323. } catch (IOException e) {
  324. error = true;
  325. break;
  326. } catch (Throwable t) {
  327. log.debug(sm.getString("ajpprocessor.header.error"), t);
  328. // 400 - Bad Request
  329. response.setStatus(400);
  330. adapter.log(request, response, 0);
  331. error = true;
  332. }
  333. // Setting up filters, and parse some request headers
  334. rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
  335. try {
  336. prepareRequest();
  337. } catch (Throwable t) {
  338. log.debug(sm.getString("ajpprocessor.request.prepare"), t);
  339. // 400 - Internal Server Error
  340. response.setStatus(400);
  341. adapter.log(request, response, 0);
  342. error = true;
  343. }
  344. // Process the request in the adapter
  345. if (!error) {
  346. try {
  347. rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
  348. adapter.service(request, response);
  349. } catch (InterruptedIOException e) {
  350. error = true;
  351. } catch (Throwable t) {
  352. log.error(sm.getString("ajpprocessor.request.process"), t);
  353. // 500 - Internal Server Error
  354. response.setStatus(500);
  355. adapter.log(request, response, 0);
  356. error = true;
  357. }
  358. }
  359. if (async && !error) {
  360. break;
  361. }
  362. // Finish the response if not done yet
  363. if (!finished) {
  364. try {
  365. finish();
  366. } catch (Throwable t) {
  367. error = true;
  368. }
  369. }
  370. // If there was an error, make sure the request is counted as
  371. // and error, and update the statistics counter
  372. if (error) {
  373. response.setStatus(500);
  374. }
  375. request.updateCounters();
  376. rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
  377. recycle();
  378. }
  379. if (async && !error) {
  380. rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  381. return SocketState.LONG;
  382. } else {
  383. rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  384. recycle();
  385. input = null;
  386. output = null;
  387. return SocketState.CLOSED;
  388. }
  389. }
  390. public SocketState asyncDispatch(SocketStatus status) throws IOException {
  391. RequestInfo rp = request.getRequestProcessor();
  392. try {
  393. rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
  394. error = !adapter.asyncDispatch(request, response, status);
  395. } catch (InterruptedIOException e) {
  396. error = true;
  397. } catch (Throwable t) {
  398. log.error(sm.getString("http11processor.request.process"), t);
  399. // 500 - Internal Server Error
  400. response.setStatus(500);
  401. adapter.log(request, response, 0);
  402. error = true;
  403. }
  404. rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  405. if (async) {
  406. if (error) {
  407. response.setStatus(500);
  408. request.updateCounters();
  409. recycle();
  410. input = null;
  411. output = null;
  412. return SocketState.CLOSED;
  413. } else {
  414. return SocketState.LONG;
  415. }
  416. } else {
  417. if (error) {
  418. response.setStatus(500);
  419. }
  420. request.updateCounters();
  421. recycle();
  422. input = null;
  423. output = null;
  424. return SocketState.CLOSED;
  425. }
  426. }
  427. // ----------------------------------------------------- ActionHook Methods
  428. /**
  429. * Send an action to the connector.
  430. *
  431. * @param actionCode Type of the action
  432. * @param param Action parameter
  433. */
  434. public void action(ActionCode actionCode, Object param) {
  435. if (actionCode == ActionCode.ACTION_COMMIT) {
  436. if (response.isCommitted())
  437. return;
  438. // Validate and write response headers
  439. try {
  440. prepareResponse();
  441. } catch (IOException e) {
  442. // Set error flag
  443. error = true;
  444. }
  445. } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
  446. if (!response.isCommitted()) {
  447. // Validate and write response headers
  448. try {
  449. prepareResponse();
  450. } catch (IOException e) {
  451. // Set error flag
  452. error = true;
  453. return;
  454. }
  455. }
  456. try {
  457. flush();
  458. } catch (IOException e) {
  459. // Set error flag
  460. error = true;
  461. }
  462. } else if (actionCode == ActionCode.ACTION_CLOSE) {
  463. // Close
  464. async = false;
  465. // End the processing of the current request, and stop any further
  466. // transactions with the client
  467. try {
  468. finish();
  469. } catch (IOException e) {
  470. // Set error flag
  471. error = true;
  472. }
  473. } else if (actionCode == ActionCode.ACTION_START) {
  474. started = true;
  475. } else if (actionCode == ActionCode.ACTION_STOP) {
  476. started = false;
  477. } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
  478. if (!certificates.isNull()) {
  479. ByteChunk certData = certificates.getByteChunk();
  480. X509Certificate jsseCerts[] = null;
  481. ByteArrayInputStream bais =
  482. new ByteArrayInputStream(certData.getBytes(),
  483. certData.getStart(),
  484. certData.getLength());
  485. // Fill the elements.
  486. try {
  487. CertificateFactory cf =
  488. CertificateFactory.getInstance("X.509");
  489. while(bais.available() > 0) {
  490. X509Certificate cert = (X509Certificate)
  491. cf.generateCertificate(bais);
  492. if(jsseCerts == null) {
  493. jsseCerts = new X509Certificate[1];
  494. jsseCerts[0] = cert;
  495. } else {
  496. X509Certificate [] temp = new X509Certificate[jsseCerts.length+1];
  497. System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length);
  498. temp[jsseCerts.length] = cert;
  499. jsseCerts = temp;
  500. }
  501. }
  502. } catch (java.security.cert.CertificateException e) {
  503. log.error(sm.getString("ajpprocessor.certs.fail"), e);
  504. return;
  505. }
  506. request.setAttribute(AbstractEndpoint.CERTIFICATE_KEY, jsseCerts);
  507. }
  508. } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
  509. // Get remote host name using a DNS resolution
  510. if (request.remoteHost().isNull()) {
  511. try {
  512. request.remoteHost().setString(InetAddress.getByName
  513. (request.remoteAddr().toString()).getHostName());
  514. } catch (IOException iex) {
  515. // Ignore
  516. }
  517. }
  518. } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
  519. // Copy from local name for now, which should simply be an address
  520. request.localAddr().setString(request.localName().toString());
  521. } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
  522. // Set the given bytes as the content
  523. ByteChunk bc = (ByteChunk) param;
  524. int length = bc.getLength();
  525. bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
  526. request.setContentLength(length);
  527. first = false;
  528. empty = false;
  529. replay = true;
  530. } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
  531. //TODO SERVLET3 - async
  532. async = true;
  533. } else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
  534. //TODO SERVLET3 - async
  535. AtomicBoolean dispatch = (AtomicBoolean)param;
  536. RequestInfo rp = request.getRequestProcessor();
  537. if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) { //async handling
  538. dispatch.set(true);
  539. endpoint.processSocket(this.socket, SocketStatus.STOP);
  540. } else {
  541. dispatch.set(false);
  542. }
  543. } else if (actionCode == ActionCode.ACTION_ASYNC_SETTIMEOUT) {
  544. //TODO SERVLET3 - async
  545. if (param==null) return;
  546. long timeout = ((Long)param).longValue();
  547. //if we are not piggy backing on a worker thread, set the timeout
  548. socket.setTimeout(timeout);
  549. } else if (actionCode == ActionCode.ACTION_ASYNC_DISPATCH) {
  550. RequestInfo rp = request.getRequestProcessor();
  551. AtomicBoolean dispatch = (AtomicBoolean)param;
  552. if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) {//async handling
  553. endpoint.processSocket(this.socket, SocketStatus.OPEN);
  554. dispatch.set(true);
  555. } else {
  556. dispatch.set(true);
  557. }
  558. }
  559. }
  560. // ------------------------------------------------------ Connector Methods
  561. /**
  562. * Set the associated adapter.
  563. *
  564. * @param adapter the new adapter
  565. */
  566. public void setAdapter(Adapter adapter) {
  567. this.adapter = adapter;
  568. }
  569. /**
  570. * Get the associated adapter.
  571. *
  572. * @return the associated adapter
  573. */
  574. public Adapter getAdapter() {
  575. return adapter;
  576. }
  577. // ------------------------------------------------------ Protected Methods
  578. /**
  579. * After reading the request headers, we have to setup the request filters.
  580. */
  581. protected void prepareRequest() {
  582. // Translate the HTTP method code to a String.
  583. byte methodCode = requestHeaderMessage.getByte();
  584. if (methodCode != Constants.SC_M_JK_STORED) {
  585. String methodName = Constants.methodTransArray[methodCode - 1];
  586. request.method().setString(methodName);
  587. }
  588. requestHeaderMessage.getBytes(request.protocol());
  589. requestHeaderMessage.getBytes(request.requestURI());
  590. requestHeaderMessage.getBytes(request.remoteAddr());
  591. requestHeaderMessage.getBytes(request.remoteHost());
  592. requestHeaderMessage.getBytes(request.localName());
  593. request.setLocalPort(requestHeaderMessage.getInt());
  594. boolean isSSL = requestHeaderMessage.getByte() != 0;
  595. if (isSSL) {
  596. request.scheme().setString("https");
  597. }
  598. // Decode headers
  599. MimeHeaders headers = request.getMimeHeaders();
  600. int hCount = requestHeaderMessage.getInt();
  601. for(int i = 0 ; i < hCount ; i++) {
  602. String hName = null;
  603. // Header names are encoded as either an integer code starting
  604. // with 0xA0, or as a normal string (in which case the first
  605. // two bytes are the length).
  606. int isc = requestHeaderMessage.peekInt();
  607. int hId = isc & 0xFF;
  608. MessageBytes vMB = null;
  609. isc &= 0xFF00;
  610. if(0xA000 == isc) {
  611. requestHeaderMessage.getInt(); // To advance the read position
  612. hName = Constants.headerTransArray[hId - 1];
  613. vMB = headers.addValue(hName);
  614. } else {
  615. // reset hId -- if the header currently being read
  616. // happens to be 7 or 8 bytes long, the code below
  617. // will think it's the content-type header or the
  618. // content-length header - SC_REQ_CONTENT_TYPE=7,
  619. // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
  620. // behaviour. see bug 5861 for more information.
  621. hId = -1;
  622. requestHeaderMessage.getBytes(tmpMB);
  623. ByteChunk bc = tmpMB.getByteChunk();
  624. vMB = headers.addValue(bc.getBuffer(),
  625. bc.getStart(), bc.getLength());
  626. }
  627. requestHeaderMessage.getBytes(vMB);
  628. if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
  629. (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
  630. // just read the content-length header, so set it
  631. long cl = vMB.getLong();
  632. if(cl < Integer.MAX_VALUE)
  633. request.setContentLength( (int)cl );
  634. } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
  635. (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
  636. // just read the content-type header, so set it
  637. ByteChunk bchunk = vMB.getByteChunk();
  638. request.contentType().setBytes(bchunk.getBytes(),
  639. bchunk.getOffset(),
  640. bchunk.getLength());
  641. }
  642. }
  643. // Decode extra attributes
  644. boolean secret = false;
  645. byte attributeCode;
  646. while ((attributeCode = requestHeaderMessage.getByte())
  647. != Constants.SC_A_ARE_DONE) {
  648. switch (attributeCode) {
  649. case Constants.SC_A_REQ_ATTRIBUTE :
  650. requestHeaderMessage.getBytes(tmpMB);
  651. String n = tmpMB.toString();
  652. requestHeaderMessage.getBytes(tmpMB);
  653. String v = tmpMB.toString();
  654. /*
  655. * AJP13 misses to forward the remotePort.
  656. * Allow the AJP connector to add this info via
  657. * a private request attribute.
  658. * We will accept the forwarded data as the remote port,
  659. * and remove it from the public list of request attributes.
  660. */
  661. if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
  662. try {
  663. request.setRemotePort(Integer.parseInt(v));
  664. } catch (NumberFormatException nfe) {
  665. }
  666. } else {
  667. request.setAttribute(n, v );
  668. }
  669. break;
  670. case Constants.SC_A_CONTEXT :
  671. requestHeaderMessage.getBytes(tmpMB);
  672. // nothing
  673. break;
  674. case Constants.SC_A_SERVLET_PATH :
  675. requestHeaderMessage.getBytes(tmpMB);
  676. // nothing
  677. break;
  678. case Constants.SC_A_REMOTE_USER :
  679. if (tomcatAuthentication) {
  680. // ignore server
  681. requestHeaderMessage.getBytes(tmpMB);
  682. } else {
  683. requestHeaderMessage.getBytes(request.getRemoteUser());
  684. }
  685. break;
  686. case Constants.SC_A_AUTH_TYPE :
  687. if (tomcatAuthentication) {
  688. // ignore server
  689. requestHeaderMessage.getBytes(tmpMB);
  690. } else {
  691. requestHeaderMessage.getBytes(request.getAuthType());
  692. }
  693. break;
  694. case Constants.SC_A_QUERY_STRING :
  695. requestHeaderMessage.getBytes(request.queryString());
  696. break;
  697. case Constants.SC_A_JVM_ROUTE :
  698. requestHeaderMessage.getBytes(request.instanceId());
  699. break;
  700. case Constants.SC_A_SSL_CERT :
  701. request.scheme().setString("https");
  702. // SSL certificate extraction is lazy, moved to JkCoyoteHandler
  703. requestHeaderMessage.getBytes(certificates);
  704. break;
  705. case Constants.SC_A_SSL_CIPHER :
  706. request.scheme().setString("https");
  707. requestHeaderMessage.getBytes(tmpMB);
  708. request.setAttribute(AbstractEndpoint.CIPHER_SUITE_KEY,
  709. tmpMB.toString());
  710. break;
  711. case Constants.SC_A_SSL_SESSION :
  712. request.scheme().setString("https");
  713. requestHeaderMessage.getBytes(tmpMB);
  714. request.setAttribute(AbstractEndpoint.SESSION_ID_KEY,
  715. tmpMB.toString());
  716. break;
  717. case Constants.SC_A_SSL_KEY_SIZE :
  718. request.setAttribute(AbstractEndpoint.KEY_SIZE_KEY,
  719. new Integer(requestHeaderMessage.getInt()));
  720. break;
  721. case Constants.SC_A_STORED_METHOD:
  722. requestHeaderMessage.getBytes(request.method());
  723. break;
  724. case Constants.SC_A_SECRET:
  725. requestHeaderMessage.getBytes(tmpMB);
  726. if (requiredSecret != null) {
  727. secret = true;
  728. if (!tmpMB.equals(requiredSecret)) {
  729. response.setStatus(403);
  730. adapter.log(request, response, 0);
  731. error = true;
  732. }
  733. }
  734. break;
  735. default:
  736. // Ignore unknown attribute for backward compatibility
  737. break;
  738. }
  739. }
  740. // Check if secret was submitted if required
  741. if ((requiredSecret != null) && !secret) {
  742. response.setStatus(403);
  743. adapter.log(request, response, 0);
  744. error = true;
  745. }
  746. // Check for a full URI (including protocol://host:port/)
  747. ByteChunk uriBC = request.requestURI().getByteChunk();
  748. if (uriBC.startsWithIgnoreCase("http", 0)) {
  749. int pos = uriBC.indexOf("://", 0, 3, 4);
  750. int uriBCStart = uriBC.getStart();
  751. int slashPos = -1;
  752. if (pos != -1) {
  753. byte[] uriB = uriBC.getBytes();
  754. slashPos = uriBC.indexOf('/', pos + 3);
  755. if (slashPos == -1) {
  756. slashPos = uriBC.getLength();
  757. // Set URI as "/"
  758. request.requestURI().setBytes
  759. (uriB, uriBCStart + pos + 1, 1);
  760. } else {
  761. request.requestURI().setBytes
  762. (uriB, uriBCStart + slashPos,
  763. uriBC.getLength() - slashPos);
  764. }
  765. MessageBytes hostMB = headers.setValue("host");
  766. hostMB.setBytes(uriB, uriBCStart + pos + 3,
  767. slashPos - pos - 3);
  768. }
  769. }
  770. MessageBytes valueMB = request.getMimeHeaders().getValue("host");
  771. parseHost(valueMB);
  772. }
  773. /**
  774. * Parse host.
  775. */
  776. public void parseHost(MessageBytes valueMB) {
  777. if (valueMB == null || (valueMB != null && valueMB.isNull()) ) {
  778. // HTTP/1.0
  779. request.setServerPort(request.getLocalPort());
  780. try {
  781. request.serverName().duplicate(request.localName());
  782. } catch (IOException e) {
  783. response.setStatus(400);
  784. adapter.log(request, response, 0);
  785. error = true;
  786. }
  787. return;
  788. }
  789. ByteChunk valueBC = valueMB.getByteChunk();
  790. byte[] valueB = valueBC.getBytes();
  791. int valueL = valueBC.getLength();
  792. int valueS = valueBC.getStart();
  793. int colonPos = -1;
  794. if (hostNameC.length < valueL) {
  795. hostNameC = new char[valueL];
  796. }
  797. boolean ipv6 = (valueB[valueS] == '[');
  798. boolean bracketClosed = false;
  799. for (int i = 0; i < valueL; i++) {
  800. char b = (char) valueB[i + valueS];
  801. hostNameC[i] = b;
  802. if (b == ']') {
  803. bracketClosed = true;
  804. } else if (b == ':') {
  805. if (!ipv6 || bracketClosed) {
  806. colonPos = i;
  807. break;
  808. }
  809. }
  810. }
  811. if (colonPos < 0) {
  812. if (request.scheme().equalsIgnoreCase("https")) {
  813. // 443 - Default HTTPS port
  814. request.setServerPort(443);
  815. } else {
  816. // 80 - Default HTTTP port
  817. request.setServerPort(80);
  818. }
  819. request.serverName().setChars(hostNameC, 0, valueL);
  820. } else {
  821. request.serverName().setChars(hostNameC, 0, colonPos);
  822. int port = 0;
  823. int mult = 1;
  824. for (int i = valueL - 1; i > colonPos; i--) {
  825. int charValue = HexUtils.getDec(valueB[i + valueS]);
  826. if (charValue == -1) {
  827. // Invalid character
  828. error = true;
  829. // 400 - Bad request
  830. response.setStatus(400);
  831. adapter.log(request, response, 0);
  832. break;
  833. }
  834. port = port + (charValue * mult);
  835. mult = 10 * mult;
  836. }
  837. request.setServerPort(port);
  838. }
  839. }
  840. /**
  841. * When committing the response, we have to validate the set of headers, as
  842. * well as setup the response filters.
  843. */
  844. protected void prepareResponse()
  845. throws IOException {
  846. response.setCommitted(true);
  847. responseHeaderMessage.reset();
  848. responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
  849. // HTTP header contents
  850. responseHeaderMessage.appendInt(response.getStatus());
  851. String message = null;
  852. if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER &&
  853. HttpMessages.isSafeInHttpHeader(response.getMessage())) {
  854. message = response.getMessage();
  855. }
  856. if (message == null){
  857. message = HttpMessages.getMessage(response.getStatus());
  858. }
  859. if (message == null) {
  860. // mod_jk + httpd 2.x fails with a null status message - bug 45026
  861. message = Integer.toString(response.getStatus());
  862. }
  863. tmpMB.setString(message);
  864. responseHeaderMessage.appendBytes(tmpMB);
  865. // Special headers
  866. MimeHeaders headers = response.getMimeHeaders();
  867. String contentType = response.getContentType();
  868. if (contentType != null) {
  869. headers.setValue("Content-Type").setString(contentType);
  870. }
  871. String contentLanguage = response.getContentLanguage();
  872. if (contentLanguage != null) {
  873. headers.setValue("Content-Language").setString(contentLanguage);
  874. }
  875. long contentLength = response.getContentLengthLong();
  876. if (contentLength >= 0) {
  877. headers.setValue("Content-Length").setLong(contentLength);
  878. }
  879. // Other headers
  880. int numHeaders = headers.size();
  881. responseHeaderMessage.appendInt(numHeaders);
  882. for (int i = 0; i < numHeaders; i++) {
  883. MessageBytes hN = headers.getName(i);
  884. int hC = Constants.getResponseAjpIndex(hN.toString());
  885. if (hC > 0) {
  886. responseHeaderMessage.appendInt(hC);
  887. }
  888. else {
  889. responseHeaderMessage.appendBytes(hN);
  890. }
  891. MessageBytes hV=headers.getValue(i);
  892. responseHeaderMessage.appendBytes(hV);
  893. }
  894. // Write to buffer
  895. responseHeaderMessage.end();
  896. output.write(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
  897. }
  898. /**
  899. * Finish AJP response.
  900. */
  901. protected void finish()
  902. throws IOException {
  903. if (!response.isCommitted()) {
  904. // Validate and write response headers
  905. try {
  906. prepareResponse();
  907. } catch (IOException e) {
  908. // Set error flag
  909. error = true;
  910. }
  911. }
  912. if (finished)
  913. return;
  914. finished = true;
  915. // Add the end message
  916. output.write(endMessageArray);
  917. }
  918. /**
  919. * Read at least the specified amount of bytes, and place them
  920. * in the input buffer.
  921. */
  922. protected boolean read(byte[] buf, int pos, int n)
  923. throws IOException {
  924. int read = 0;
  925. int res = 0;
  926. while (read < n) {
  927. res = input.read(buf, read + pos, n - read);
  928. if (res > 0) {
  929. read += res;
  930. } else {
  931. throw new IOException(sm.getString("ajpprotocol.failedread"));
  932. }
  933. }
  934. return true;
  935. }
  936. /** Receive a chunk of data. Called to implement the
  937. * 'special' packet in ajp13 and to receive the data
  938. * after we send a GET_BODY packet
  939. */
  940. public boolean receive() throws IOException {
  941. first = false;
  942. bodyMessage.reset();
  943. if (!readMessage(bodyMessage)) {
  944. // Invalid message
  945. return false;
  946. }
  947. // No data received.
  948. if (bodyMessage.getLen() == 0) {
  949. // just the header
  950. // Don't mark 'end of stream' for the first chunk.
  951. return false;
  952. }
  953. int blen = bodyMessage.peekInt();
  954. if (blen == 0) {
  955. return false;
  956. }
  957. bodyMessage.getBytes(bodyBytes);
  958. empty = false;
  959. return true;
  960. }
  961. /**
  962. * Get more request body data from the web server and store it in the
  963. * internal buffer.
  964. *
  965. * @return true if there is more data, false if not.
  966. */
  967. private boolean refillReadBuffer() throws IOException {
  968. // If the server returns an empty packet, assume that that end of
  969. // the stream has been reached (yuck -- fix protocol??).
  970. // FORM support
  971. if (replay) {
  972. endOfStream = true; // we've read everything there is
  973. }
  974. if (endOfStream) {
  975. return false;
  976. }
  977. // Request more data immediately
  978. output.write(getBodyMessageArray);
  979. boolean moreData = receive();
  980. if( !moreData ) {
  981. endOfStream = true;
  982. }
  983. return moreData;
  984. }
  985. /**
  986. * Read an AJP message.
  987. *
  988. * @return true if the message has been read, false if the short read
  989. * didn't return anything
  990. * @throws IOException any other failure, including incomplete reads
  991. */
  992. protected boolean readMessage(AjpMessage message)
  993. throws IOException {
  994. byte[] buf = message.getBuffer();
  995. int headerLength = message.getHeaderLength();
  996. read(buf, 0, headerLength);
  997. int messageLength = message.processHeader();
  998. if (messageLength < 0) {
  999. // Invalid AJP header signature
  1000. // TODO: Throw some exception and close the connection to frontend.
  1001. return false;
  1002. }
  1003. else if (messageLength == 0) {
  1004. // Zero length message.
  1005. return true;
  1006. }
  1007. else {
  1008. read(buf, headerLength, messageLength);
  1009. return true;
  1010. }
  1011. }
  1012. /**
  1013. * Recycle the processor.
  1014. */
  1015. public void recycle() {
  1016. // Recycle Request object
  1017. first = true;
  1018. endOfStream = false;
  1019. empty = true;
  1020. replay = false;
  1021. finished = false;
  1022. request.recycle();
  1023. response.recycle();
  1024. certificates.recycle();
  1025. async = false;
  1026. }
  1027. /**
  1028. * Callback to write data from the buffer.
  1029. */
  1030. protected void flush()
  1031. throws IOException {
  1032. // Send the flush message
  1033. output.write(flushMessageArray);
  1034. }
  1035. // ------------------------------------- InputStreamInputBuffer Inner Class
  1036. /**
  1037. * This class is an input buffer which will read its data from an input
  1038. * stream.
  1039. */
  1040. protected class SocketInputBuffer
  1041. implements InputBuffer {
  1042. /**
  1043. * Read bytes into the specified chunk.
  1044. */
  1045. public int doRead(ByteChunk chunk, Request req )
  1046. throws IOException {
  1047. if (endOfStream) {
  1048. return -1;
  1049. }
  1050. if (first && req.getContentLengthLong() > 0) {
  1051. // Handle special first-body-chunk
  1052. if (!receive()) {
  1053. return 0;
  1054. }
  1055. } else if (empty) {
  1056. if (!refillReadBuffer()) {
  1057. return -1;
  1058. }
  1059. }
  1060. ByteChunk bc = bodyBytes.getByteChunk();
  1061. chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
  1062. empty = true;
  1063. return chunk.getLength();
  1064. }
  1065. }
  1066. // ----------------------------------- OutputStreamOutputBuffer Inner Class
  1067. /**
  1068. * This class is an output buffer which will write data to an output
  1069. * stream.
  1070. */
  1071. protected class SocketOutputBuffer
  1072. implements OutputBuffer {
  1073. /**
  1074. * Write chunk.
  1075. */
  1076. public int doWrite(ByteChunk chunk, Response res)
  1077. throws IOException {
  1078. if (!response.isCommitted()) {
  1079. // Validate and write response headers
  1080. try {
  1081. prepareResponse();
  1082. } catch (IOException e) {
  1083. // Set error flag
  1084. error = true;
  1085. }
  1086. }
  1087. int len = chunk.getLength();
  1088. // 4 - hardcoded, byte[] marshaling overhead
  1089. // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE)
  1090. int chunkSize = Constants.MAX_SEND_SIZE + packetSize - Constants.MAX_PACKET_SIZE;
  1091. int off = 0;
  1092. while (len > 0) {
  1093. int thisTime = len;
  1094. if (thisTime > chunkSize) {
  1095. thisTime = chunkSize;
  1096. }
  1097. len -= thisTime;
  1098. responseHeaderMessage.reset();
  1099. responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
  1100. responseHeaderMessage.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime);
  1101. responseHeaderMessage.end();
  1102. output.write(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
  1103. off += thisTime;
  1104. }
  1105. return chunk.getLength();
  1106. }
  1107. }
  1108. }