PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

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

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