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 com .threedr3am .bug .tomcat .ajp .support ;
18+
19+ import java .io .IOException ;
20+ import java .io .InputStream ;
21+ import java .net .Socket ;
22+ import java .util .Arrays ;
23+ import javax .net .SocketFactory ;
24+ import org .apache .coyote .ajp .Constants ;
25+
26+ /**
27+ * AJP client that is not (yet) a full AJP client implementation as it just
28+ * provides the functionality required for the unit tests. The client uses
29+ * blocking IO throughout.
30+ */
31+ public class SimpleAjpClient {
32+
33+ private static final int AJP_PACKET_SIZE = 8192 ;
34+ private static final byte [] AJP_CPING ;
35+
36+ static {
37+ TesterAjpMessage ajpCping = new TesterAjpMessage (16 );
38+ ajpCping .reset ();
39+ ajpCping .appendByte (Constants .JK_AJP13_CPING_REQUEST );
40+ ajpCping .end ();
41+ AJP_CPING = new byte [ajpCping .getLen ()];
42+ System .arraycopy (ajpCping .getBuffer (), 0 , AJP_CPING , 0 ,
43+ ajpCping .getLen ());
44+ }
45+
46+ private String host = "localhost" ;
47+ private int port = -1 ;
48+ private Socket socket = null ;
49+
50+ public int getPort () {
51+ return port ;
52+ }
53+
54+ public void connect (String host , int port ) throws IOException {
55+ this .host = host ;
56+ this .port = port ;
57+ socket = SocketFactory .getDefault ().createSocket (host , port );
58+ }
59+
60+ public void disconnect () throws IOException {
61+ socket .close ();
62+ socket = null ;
63+ }
64+
65+ /**
66+ * Create a message to request the given URL.
67+ */
68+ public TesterAjpMessage createForwardMessage (String url ) {
69+ return createForwardMessage (url , 2 );
70+ }
71+
72+ public TesterAjpMessage createForwardMessage (String url , int method ) {
73+
74+ TesterAjpMessage message = new TesterAjpMessage (AJP_PACKET_SIZE );
75+ message .reset ();
76+
77+ // Set the header bytes
78+ message .getBuffer ()[0 ] = 0x12 ;
79+ message .getBuffer ()[1 ] = 0x34 ;
80+
81+ // Code 2 for forward request
82+ message .appendByte (Constants .JK_AJP13_FORWARD_REQUEST );
83+
84+ // HTTP method, GET = 2
85+ message .appendByte (method );
86+
87+ // Protocol
88+ message .appendString ("http" );
89+
90+ // Request URI
91+ message .appendString (url );
92+
93+ // Remote address
94+ message .appendString ("10.0.0.1" );
95+
96+ // Remote host
97+ message .appendString ("client.dev.local" );
98+
99+ // Server name
100+ message .appendString (host );
101+
102+ // Port
103+ message .appendInt (port );
104+
105+ // Is ssl
106+ message .appendByte (0x00 );
107+
108+ return message ;
109+ }
110+
111+
112+ public TesterAjpMessage createBodyMessage (byte [] data ) {
113+
114+ TesterAjpMessage message = new TesterAjpMessage (AJP_PACKET_SIZE );
115+ message .reset ();
116+
117+ // Set the header bytes
118+ message .getBuffer ()[0 ] = 0x12 ;
119+ message .getBuffer ()[1 ] = 0x34 ;
120+
121+ message .appendBytes (data , 0 , data .length );
122+ message .end ();
123+
124+ return message ;
125+ }
126+
127+
128+ /**
129+ * Sends an TesterAjpMessage to the server and returns the response message.
130+ */
131+ public void sendMessage (TesterAjpMessage headers )
132+ throws IOException {
133+ sendMessage (headers , null );
134+ }
135+
136+ public void sendMessage (TesterAjpMessage headers ,
137+ TesterAjpMessage body ) throws IOException {
138+ // Send the headers
139+ socket .getOutputStream ().write (
140+ headers .getBuffer (), 0 , headers .getLen ());
141+ if (body != null ) {
142+ // Send the body of present
143+ socket .getOutputStream ().write (
144+ body .getBuffer (), 0 , body .getLen ());
145+ }
146+ }
147+ /**
148+ * Reads a message from the server.
149+ */
150+ public byte [] readMessage () throws IOException {
151+
152+ InputStream is = socket .getInputStream ();
153+
154+ TesterAjpMessage message = new TesterAjpMessage (AJP_PACKET_SIZE );
155+
156+ byte [] buf = message .getBuffer ();
157+ int headerLength = message .getHeaderLength ();
158+
159+ read (is , buf , 0 , headerLength );
160+
161+ int messageLength = message .processHeader (false );
162+ if (messageLength < 0 ) {
163+ throw new IOException ("Invalid AJP message length" );
164+ } else if (messageLength == 0 ) {
165+ return null ;
166+ } else {
167+ if (messageLength > buf .length ) {
168+ throw new IllegalArgumentException ("Message too long [" +
169+ Integer .valueOf (messageLength ) +
170+ "] for buffer length [" +
171+ Integer .valueOf (buf .length ) + "]" );
172+ }
173+ read (is , buf , headerLength , messageLength );
174+ return Arrays .copyOfRange (buf , headerLength , headerLength + messageLength );
175+ }
176+ }
177+
178+ protected boolean read (InputStream is , byte [] buf , int pos , int n )
179+ throws IOException {
180+
181+ int read = 0 ;
182+ int res = 0 ;
183+ while (read < n ) {
184+ res = is .read (buf , read + pos , n - read );
185+ if (res > 0 ) {
186+ read += res ;
187+ } else {
188+ throw new IOException ("Read failed" );
189+ }
190+ }
191+ return true ;
192+ }
193+ }
0 commit comments