2 ** \file Ajp13Socket.cpp
4 ** \author grymse@alhem.net
7 Copyright (C) 2007 Anders Hedstrom
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #pragma warning(disable:4786)
26 #include "Ajp13Socket.h"
28 #include "HttpRequest.h"
29 #include "HttpResponse.h"
33 #ifdef SOCKETS_NAMESPACE
34 namespace SOCKETS_NAMESPACE
{
44 // --------------------------------------------------------------------------------------
45 Ajp13Socket::Ajp13Socket(ISocketHandler
& h
) : AjpBaseSocket(h
)
52 // --------------------------------------------------------------------------------------
53 void Ajp13Socket::OnHeader( short id
, short len
)
57 fprintf(stderr
, "ABORT: bad packet id: %x\n", id
);
62 DEB(fprintf(stderr
, "Packet size: %d bytes\n", len
);)
67 // --------------------------------------------------------------------------------------
68 void Ajp13Socket::ReceiveBody(const char *buf
, size_t sz
)
70 if (sz
- 2 > m_body_size_left
)
72 fprintf(stderr
, "More body data received than expected\n");
77 m_req
.Write( buf
+ 2, sz
- 2 );
78 m_body_size_left
-= sz
- 2;
80 // request more body data
89 // 0x3 Send Body Chunk
92 // 0x6 Get Body Chunk <------
95 put_byte(msg
, ptr
, 0x06); // GET_BODY_CHUNK;
96 put_integer(msg
, ptr
, 1000); // request 1000 bytes
98 short len
= htons( ptr
- 4 );
99 memcpy( msg
+ 2, &len
, 2 );
108 // no more body data left to read - execute
114 // --------------------------------------------------------------------------------------
115 void Ajp13Socket::ReceiveForwardRequest( const char *buf
, size_t sz
)
120 get_byte(buf
, ptr
); // skip first byte: prefix_code
121 unsigned char method
= get_byte(buf
, ptr
);
122 std::string protocol
= get_string(buf
, ptr
);
123 std::string req_uri
= get_string(buf
, ptr
);
124 std::string remote_addr
= get_string(buf
, ptr
);
125 std::string remote_host
= get_string(buf
, ptr
);
126 std::string server_name
= get_string(buf
, ptr
);
127 short server_port
= get_integer(buf
, ptr
);
128 bool is_ssl
= get_boolean(buf
, ptr
);
130 std::string method_str
= Utility::l2string( method
);
131 std::map
<int, std::string
>::const_iterator it
= Init
.Method
.find( method
);
132 if (it
!= Init
.Method
.end())
134 method_str
= it
-> second
;
136 m_req
.SetHttpMethod( method_str
);
137 m_req
.SetHttpVersion( protocol
);
138 m_req
.SetUri( req_uri
);
139 m_req
.SetRemoteAddr( remote_addr
);
140 m_req
.SetRemoteHost( remote_host
);
141 m_req
.SetServerName( server_name
);
142 m_req
.SetServerPort( server_port
);
143 m_req
.SetIsSsl( is_ssl
);
146 short num_headers
= get_integer(buf
, ptr
);
147 for (int i
= 0; i
< num_headers
; i
++)
150 switch ( (unsigned char)buf
[ptr
]) // 0xa0
154 unsigned short x
= (unsigned short)get_integer(buf
, ptr
);
155 std::map
<int, std::string
>::const_iterator it
;
156 if ( (it
= Init
.Header
.find(x
)) != Init
.Header
.end())
162 fprintf(stderr
, "Unknown header key value: %x\n", x
);
169 key
= get_string(buf
, ptr
);
171 if (Utility::ToLower(key
) == "cookie" || Utility::ToLower(key
) == "cookie2")
172 m_req
.AddCookie(get_string(buf
, ptr
));
174 m_req
.SetHeader(key
, get_string(buf
, ptr
));
177 // size left to read from web server
178 m_body_size_left
= m_req
.ContentLength();
181 while ( (unsigned char)buf
[ptr
] != 0xff)
184 unsigned char code
= buf
[ptr
++];
187 case 10: // req_attribute, attribute name follow
188 key
= get_string(buf
, ptr
);
192 std::map
<int, std::string
>::const_iterator it
= Init
.Attribute
.find( code
);
193 if (it
!= Init
.Attribute
.end())
199 fprintf(stderr
, "Unknown attribute key: 0x%02x\n", buf
[ptr
]);
204 m_req
.SetAttribute(key
, get_string(buf
, ptr
));
207 // execute at once if no body data
208 if (!m_body_size_left
)
214 // open temporary file for body data
215 m_req
.InitBody( m_body_size_left
);
220 // --------------------------------------------------------------------------------------
221 void Ajp13Socket::ReceiveShutdown( const char *buf
, size_t sz
)
226 // --------------------------------------------------------------------------------------
227 void Ajp13Socket::ReceivePing( const char *buf
, size_t sz
)
232 // --------------------------------------------------------------------------------------
233 void Ajp13Socket::ReceiveCPing( const char *buf
, size_t sz
)
238 // --------------------------------------------------------------------------------------
239 void Ajp13Socket::Execute()
241 // parse form data / query_string and cookie header if available
250 // --------------------------------------------------------------------------------------
251 void Ajp13Socket::Respond(const HttpResponse
& res
)
258 // 0x3 Send Body Chunk
261 // 0x6 Get Body Chunk
264 // check content length
265 if (!res
.ContentLength() && res
.GetFile().size())
267 // res.SetContentLength( res.GetFile().size() );
273 put_byte(msg
, ptr
, 0x04); // send headers
274 put_integer(msg
, ptr
, res
.HttpStatusCode() );
275 put_string(msg
, ptr
, res
.HttpStatusMsg() );
276 put_integer(msg
, ptr
, (short)res
.Headers().size() );
277 for (std::map
<std::string
, std::string
>::const_iterator it
= res
.Headers().begin(); it
!= res
.Headers().end(); ++it
)
279 std::map
<std::string
, int>::const_iterator it2
= Init
.ResponseHeader
.find( it
-> first
);
280 if (it2
!= Init
.ResponseHeader
.end())
282 put_integer(msg
, ptr
, it2
-> second
);
286 put_string(msg
, ptr
, it
-> first
);
288 put_string(msg
, ptr
, it
-> second
);
290 std::list
<std::string
> vec
= res
.CookieNames();
292 for (std::list
<std::string
>::iterator it
= vec
.begin(); it
!= vec
.end(); it
++)
294 std::map
<std::string
, int>::const_iterator it2
= Init
.ResponseHeader
.find( "set-cookie" );
295 if (it2
!= Init
.ResponseHeader
.end())
297 put_integer(msg
, ptr
, it2
-> second
);
301 put_string(msg
, ptr
, "set-cookie");
303 put_string(msg
, ptr
, res
.Cookie(*it
) );
307 short len
= htons( ptr
- 4 );
308 memcpy( msg
+ 2, &len
, 2 );
312 m_res_file
= &res
.GetFile();
318 // --------------------------------------------------------------------------------------
319 void Ajp13Socket::OnTransferLimit()
326 size_t n
= m_res_file
-> fread(msg
+ 7, 1, 8100);
330 put_byte(msg
, ptr
, 0x03); // send body chunk
331 put_integer(msg
, ptr
, (short)n
);
334 short len
= htons( ptr
- 4 );
335 memcpy( msg
+ 2, &len
, 2 );
338 if (GetOutputLength() > 1)
340 SetTransferLimit( 1 );
345 n
= m_res_file
-> fread(msg
+ 7, 1, 8100);
347 if (!GetOutputLength()) // all body data sent and no data in output buffer - send end response
351 put_byte(msg
, ptr
, 0x05); // end response
352 put_boolean(msg
, ptr
, false); // reuse
355 - but with m_req.Reset() and res.Reset() it should be possible
356 - also reset any AjpBaseSocket/Ajp13Socket specific states
359 short len
= htons( ptr
- 4 );
360 memcpy( msg
+ 2, &len
, 2 );
367 // --------------------------------------------------------------------------------------
368 void Ajp13Socket::OnPacket( const char *buf
, size_t sz
)
370 DEB(fprintf(stderr
, "OnPacket: %d bytes, code 0x%02x %02x %02x %02x\n", sz
, *buf
, buf
[1], buf
[2], buf
[3]);)
372 // check body size left to read, if non-zero packet is body data
373 if (m_body_size_left
) // must be a body packet
375 ReceiveBody(buf
, sz
);
380 case 0x2: // Forward Request
381 ReceiveForwardRequest(buf
, sz
);
383 case 0x7: // Shutdown
384 ReceiveShutdown(buf
, sz
);
387 ReceivePing(buf
, sz
);
390 ReceiveCPing(buf
, sz
);
393 fprintf(stderr
, "Unknown packet type: 0x%02x\n", *buf
);
400 #ifdef SOCKETS_NAMESPACE
401 } // namespace SOCKETS_NAMESPACE {