Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / apps / JAWS / server / HTTP_Response.cpp
blob65924b31cd9c9686f6e4ce4b5ba663ad961e2f4b
1 #include "ace/OS_NS_stdio.h"
2 #include "ace/OS_NS_string.h"
3 #include "ace/OS_NS_ctype.h"
4 #include "ace/Process.h"
5 #include "ace/Mem_Map.h"
6 #include "ace/Log_Msg.h"
8 #include "HTTP_Response.h"
9 #include "HTTP_Request.h"
10 #include "HTTP_Helpers.h"
11 #include "HTTP_Config.h"
12 #include "JAWS_IO.h"
14 #if defined (ACE_JAWS_BASELINE)
15 static char * const EMPTY_HEADER = "";
16 #else
17 static const char * const EMPTY_HEADER = "";
18 #endif /* ACE_JAWS_BASELINE */
20 HTTP_Response::HTTP_Response (JAWS_IO &io, HTTP_Request &request)
21 : io_(io), request_(request)
25 HTTP_Response::HTTP_Response (HTTP_Request &request, JAWS_IO &io)
26 : io_(io), request_(request)
30 HTTP_Response::~HTTP_Response ()
32 #if defined (ACE_JAWS_BASELINE)
33 if (this->HTTP_HEADER != EMPTY_HEADER)
34 delete [] this->HTTP_HEADER;
35 // The [] is important. Without it, there was a huge memory leak!
36 #endif /* ACE_JAWS_BASELINE */
39 void
40 HTTP_Response::process_request(HTTP_Response &response)
42 response.process_request();
45 void
46 HTTP_Response::process_request ()
48 ACE_DEBUG ((LM_DEBUG, " (%t) processing request: %s\n",
49 this->request_.status_string ()));
51 switch (this->request_.status ())
53 case HTTP_Status_Code::STATUS_OK :
55 if (this->request_.cgi ())
57 this->cgi_response ();
59 else
61 this->normal_response ();
64 break;
66 default:
67 this->error_response (this->request_.status (),
68 this->request_.status_string ());
72 void
73 HTTP_Response::error_response (int status_code, const char *log_message)
75 ACE_DEBUG ((LM_DEBUG, "(%t) [%s %s %s] %s\n",
76 this->request_.method () ? this->request_.method () : "-",
77 this->request_.uri () ? this->request_.uri () : "-",
78 this->request_.version() ? this->request_.version () : "-",
79 log_message ? log_message : "-"));
81 static char const error_header1[] =
82 "%s %d %s\r\n"
83 "Server: JAWS/1.0prebeta\r\n"
84 "Content-type: text/html\r\n"
85 "Content-length: %d\r\n"
86 "\r\n"
87 "%s"
90 static char const error_header2[] =
91 "%s %d %s\r\n"
92 "Server: JAWS/1.0prebeta\r\n"
93 "WWW-Authenticate: Basic realm=\"JAWS_authorization\"\r\n"
94 "Content-type: text/html\r\n"
95 "Content-length: %d\r\n"
96 "\r\n"
97 "%s"
100 static char const error_message[] =
101 "<html>\n"
102 "<head><title>Server error message</title></head>\n"
103 "<body>\n"
104 "<h1>Error %d: %s</h1>\n"
105 "The request could not be completed because:\n %s\n"
106 "</body>\n"
107 "</html>\n"
111 char *buf = 0;
112 char buf1[4 * BUFSIZ];
113 char buf2[BUFSIZ];
115 int length;
116 const char *error_header = error_header1;
118 if (status_code == HTTP_Status_Code::STATUS_UNAUTHORIZED)
119 error_header = error_header2;
121 length =
122 ACE_OS::sprintf (buf2, error_message,
123 status_code, HTTP_Status_Code::instance ()[status_code],
124 log_message);
126 if (this->request_.version () == 0
127 || ACE_OS::strcmp ("HTTP/0.9", this->request_.version ()) == 0)
128 buf = buf2;
129 else
131 length =
132 ACE_OS::sprintf (buf1, error_header,
133 this->request_.version(), status_code,
134 HTTP_Status_Code::instance ()[status_code],
135 length,
136 buf2);
137 buf = buf1;
140 this->io_.send_error_message (buf, length);
143 void
144 HTTP_Response::normal_response ()
146 const char *hv = 0;;
148 ACE_DEBUG ((LM_DEBUG, " (%t) %s request for %s [%s], version %s\n",
149 request_.method (), request_.uri (), request_.path (),
150 (request_.version () ? request_.version () : "HTTP/0.9")));
152 switch (this->request_.type ())
154 case HTTP_Request::GET :
156 this->build_headers ();
157 this->io_.transmit_file (this->request_.path (),
158 this->HTTP_HEADER,
159 this->HTTP_HEADER_LENGTH,
160 this->HTTP_TRAILER,
161 this->HTTP_TRAILER_LENGTH);
162 break;
164 case HTTP_Request::HEAD :
165 this->build_headers ();
166 this->io_.send_confirmation_message (this->HTTP_HEADER,
167 this->HTTP_HEADER_LENGTH);
168 break;
170 case HTTP_Request::POST :
171 // What to do here?
172 // Standard says this is implementation dependent.
173 // Examples: annotations, page updates, etc.
174 // This may be a good place to stick CORBA stuff,
175 // and mobile code.
176 this->error_response (HTTP_Status_Code::STATUS_NOT_IMPLEMENTED,
177 "Requested method is not implemented.");
178 break;
180 case HTTP_Request::PUT :
181 // Only commit to this if we can authenticate it
183 // if there is no Authentication: header on the incoming request,
184 // deny it
185 hv = this->request_.headers ()["Authorization"].value ();
186 if (hv == 0 || *hv == '\0')
187 this->error_response (HTTP_Status_Code::STATUS_UNAUTHORIZED,
188 "Unauthorized to use PUT method");
189 else if (ACE_OS::strncmp (hv, "Basic ", 6) != 0)
190 // ``6'' is the length of the string "Basic "
191 this->error_response (HTTP_Status_Code::STATUS_UNAUTHORIZED,
192 "Unknown authorization method");
193 else
195 ACE_Mem_Map mmapfile;
196 const char *hvv = hv + 6;
197 // Skip past the string "Basic "
198 char *buf = new char [ACE_OS::strlen (hv)];
199 char *auth
200 = HTTP_Helper::HTTP_decode_base64 (ACE_OS::strcpy (buf, hvv));
202 if (mmapfile.map (ACE_TEXT ("jaws.auth")) != -1
203 && auth != 0
204 && ACE_OS::strstr((const char *) mmapfile.addr (), auth) != 0)
205 this->io_.receive_file (this->request_.path (),
206 this->request_.data (),
207 this->request_.data_length (),
208 this->request_.content_length ());
209 else
210 this->error_response (HTTP_Status_Code::STATUS_UNAUTHORIZED,
211 "Invalid authorization attempt");
212 delete [] buf;
214 break;
216 default :
217 this->error_response (HTTP_Status_Code::STATUS_NOT_IMPLEMENTED,
218 "Requested method is not implemented.");
223 void
224 HTTP_Response::cgi_response ()
226 ACE_Process_Options cgi_options;
228 if (this->request_.cgi_args ())
229 cgi_options.command_line ("%s %s",
230 this->request_.path (),
231 this->request_.cgi_args ());
232 else
233 cgi_options.command_line ("%s", this->request_.path ());
235 // Build environment variables
236 cgi_options.setenv (ACE_TEXT ("SERVER_SOFTWARE"), ACE_TEXT ("%s"), ACE_TEXT ("JAWS/1.0"));
237 cgi_options.setenv (ACE_TEXT ("SERVER_NAME"), ACE_TEXT ("%s"), ACE_TEXT ("localhost"));
238 cgi_options.setenv (ACE_TEXT ("GATEWAY_INTERFACE"), ACE_TEXT ("%s"), ACE_TEXT ("CGI/1.1"));
240 cgi_options.setenv (ACE_TEXT ("SERVER_PROTOCOL"), ACE_TEXT ("%s"),
241 this->request_.version ()
242 ? this->request_.version ()
243 : "HTTP/0.9");
244 cgi_options.setenv (ACE_TEXT ("SERVER_PORT"), ACE_TEXT ("%d"), 5432);
246 cgi_options.setenv (ACE_TEXT ("REQUEST_METHOD"), ACE_TEXT ("%s"), this->request_.method ());
248 if (this->request_.path_info ())
250 cgi_options.setenv (ACE_TEXT ("PATH_INFO"), ACE_TEXT ("%s"),
251 this->request_.path_info ());
252 cgi_options.setenv (ACE_TEXT ("PATH_TRANSLATED"),
253 ACE_TEXT ("%s/%s"),
254 HTTP_Config::instance ()->document_root (),
255 this->request_.path_info ());
258 cgi_options.setenv (ACE_TEXT ("SCRIPT_NAME"),
259 ACE_TEXT ("%s"),
260 this->request_.uri ());
262 if (this->request_.query_string ())
263 cgi_options.setenv (ACE_TEXT ("QUERY_STRING"),
264 ACE_TEXT ("%s"),
265 this->request_.query_string ());
267 if (this->request_.cgi_env ())
268 for (size_t i = 0; this->request_.cgi_env ()[i]; i += 2)
269 cgi_options.setenv (ACE_TEXT_CHAR_TO_TCHAR (this->request_.cgi_env ()[i]),
270 ACE_TEXT ("%s"),
271 ACE_TEXT_CHAR_TO_TCHAR (this->request_.cgi_env ()[i+1]));
273 ACE_TCHAR buf[BUFSIZ];
274 ACE_TCHAR *p = 0, *q = 0;
275 ACE_OS::strcpy (buf, ACE_TEXT ("HTTP_"));
276 p = q = buf + ACE_OS::strlen (buf);
278 for (size_t i = 0; i < HTTP_Request::NUM_HEADER_STRINGS; i++)
280 int j = 0;
282 for (char c; (c = this->request_.header_strings (i)[j++]) != '\0'; )
283 if (ACE_OS::ace_isalpha (c))
284 *q++ = ACE_OS::ace_toupper (c);
285 else if (c == '-')
286 *q++ = '_';
287 else
288 *q++ = c;
290 *q = '\0';
292 const char *hv = this->request_.header_values (i);
294 if (hv && *hv)
295 cgi_options.setenv (buf, "%s", hv);
296 q = p;
299 cgi_options.set_handles (this->io_.handle (),
300 this->io_.handle (),
301 this->io_.handle ());
303 this->build_headers ();
304 this->io_.send_confirmation_message (this->HTTP_HEADER,
305 this->HTTP_HEADER_LENGTH);
306 // ACE::send (this->io_.handle (),
307 // this->HTTP_HEADER, this->HTTP_HEADER_LENGTH);
309 // Exec the CGI program.
310 ACE_Process cgi_process;
311 cgi_process.spawn (cgi_options);
312 // cgi_process.wait ();
315 void
316 HTTP_Response::build_headers ()
318 // At this point, we should really determine the type of request
319 // this is, and build the appropriate header.
321 // Let's assume this is HTML for now. Unless the request is CGI,
322 // then do not include content-* headers.
324 if (this->request_.version () == 0
325 || ACE_OS::strcmp ("HTTP/0.9", this->request_.version ()) == 0)
327 HTTP_HEADER = EMPTY_HEADER;
328 HTTP_HEADER_LENGTH = 0;
330 else
332 #if defined (ACE_JAWS_BASELINE)
333 HTTP_HEADER = new char[BUFSIZ * 4];
335 // We assume that at this point everything is OK
336 HTTP_HEADER_LENGTH =
337 ACE_OS::sprintf (HTTP_HEADER, "%s", "HTTP/1.0 200 OK\r\n");
339 char date_ptr [40];
340 // 40 bytes is the maximum length needed to store the date
342 if (HTTP_Helper::HTTP_date (date_ptr) != 0)
343 HTTP_HEADER_LENGTH +=
344 ACE_OS::sprintf (HTTP_HEADER+HTTP_HEADER_LENGTH,
345 "Date: %s\r\n", date_ptr);
347 if (! this->request_.cgi ()) {
348 HTTP_HEADER_LENGTH +=
349 ACE_OS::sprintf (HTTP_HEADER+HTTP_HEADER_LENGTH,
350 "Content-type: %s\r\n",
351 "text/html");
353 struct stat file_stat;
354 // If possible, add the Content-length field to the header.
355 // @@ Note that using 'ACE_OS::stat' is a hack. Normally, a
356 // web browser will have a 'virtual' file system. In a VFS,
357 // 'stat' might not reference the correct location.
358 if ((this->request_.type () == HTTP_Request::GET) &&
359 (ACE_OS::stat (this->request_.path (), &file_stat) == 0))
361 HTTP_HEADER_LENGTH +=
362 ACE_OS::sprintf (HTTP_HEADER+HTTP_HEADER_LENGTH,
363 "Content-length: %u\r\n", file_stat.st_size);
366 // Complete header with empty line and adjust header length.
367 HTTP_HEADER[HTTP_HEADER_LENGTH++] = '\r';
368 HTTP_HEADER[HTTP_HEADER_LENGTH++] = '\n';
370 #else
371 if (! this->request_.cgi ())
372 HTTP_HEADER = "HTTP/1.0 200 OK\r\n"
373 "Content-type: text/html\r\n\r\n";
374 else
375 HTTP_HEADER = "HTTP/1.0 200 OK\r\n";
377 HTTP_HEADER_LENGTH = ACE_OS::strlen (HTTP_HEADER);
379 #endif /* ACE_JAWS_BASELINE */
382 HTTP_TRAILER = "";
383 HTTP_TRAILER_LENGTH = 0;