Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
HttpServer.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: NetEx.lib
6  FILE: HttpServer.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Network Server Pump for HTTP Server
13 */
14 
15 
16 #include "MemDebug.h"
17 #include "HttpServer.h"
18 #include "NetLayer.h"
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 
24 // +-------------------------------------------------------------------+
25 
26 HttpServer::HttpServer(WORD port, int poolsize)
27  : NetServer(port, poolsize)
28 {
29  http_server_name = "Generic HttpServer 1.0";
30 }
31 
33 { }
34 
35 // +--------------------------------------------------------------------+
36 
37 Text
39 {
40  HttpRequest request(msg);
41  HttpResponse response;
42 
43  request.SetClientAddr(addr);
44 
45  switch (request.Method()) {
47  if (DoGet(request, response))
48  return response;
49 
51  if (DoPost(request, response))
52  return response;
53 
55  if (DoHead(request, response))
56  return response;
57  }
58 
59  return ErrorResponse();
60 }
61 
62 // +--------------------------------------------------------------------+
63 
64 Text
66 {
67  return http_server_name;
68 }
69 
70 void
71 HttpServer::SetServerName(const char* name)
72 {
73  http_server_name = name;
74 }
75 
76 // +--------------------------------------------------------------------+
77 
78 Text
80 {
81  Text response = "HTTP/1.1 200 OK\nServer: ";
82  response += http_server_name;
83  response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n";
84 
85  return response;
86 }
87 
88 Text
90 {
91  Text response = "HTTP/1.1 500 Internal Server Error\nServer:";
92  response += http_server_name;
93  response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n";
94 
95  response += "<html><head><title>";
96  response += http_server_name;
97  response += " Error</title></head>\n";
98  response += "<body bgcolor=\"black\" text=\"white\">\n<h1>";
99  response += http_server_name;
100  response += "</h1>\n<p>Veruca... sweetheart... angel... I'm not a magician!\n";
101  response += "</body></html>\n\n";
102 
103  return response;
104 }
105 
106 // +--------------------------------------------------------------------+
107 
108 bool
110 {
111  char buffer[1024];
112  Text content;
113 
114  content = "<html><head><title>";
115  content += http_server_name;
116  content += "</title></head>\n";
117  content += "<body bgcolor=\"white\" text=\"black\">\n<h1>";
118  content += http_server_name;
119  content += "</h1>\n";
120  content += "<br><h3>Client Address:</h3><p>\n";
121 
122  sprintf_s(buffer, "%d.%d.%d.%d:%d<br><br>\n",
123  client_addr.B1(),
124  client_addr.B2(),
125  client_addr.B3(),
126  client_addr.B4(),
127  client_addr.Port());
128 
129  content += buffer;
130  content += "<h3>Request Method:</h3><p>\n";
131 
132  switch (request.Method()) {
134  content += "GET";
135  break;
136 
138  content += "POST";
139  break;
140 
142  content += "HEAD";
143  break;
144 
145  default:
146  content += "(unsupported?)";
147  break;
148  }
149 
150  content += "<br>\n";
151  content += "<br><h3>URI Requested:</h3><p>\n";
152  content += request.URI();
153  content += "<br>\n";
154 
155  if (request.GetQuery().size() > 0) {
156  content += "<br><h3>Query Parameters:</h3>\n";
157 
158  ListIter<HttpParam> q_iter = request.GetQuery();
159  while (++q_iter) {
160  HttpParam* q = q_iter.value();
161  sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", q->name.data(), q->value.data());
162  content += buffer;
163  }
164  }
165 
166  content += "<br><h3>Request Headers:</h3>\n";
167  ListIter<HttpParam> h_iter = request.GetHeaders();
168  while (++h_iter) {
169  HttpParam* h = h_iter.value();
170  sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", h->name.data(), h->value.data());
171  content += buffer;
172  }
173 
174  content += "</body></html>\n\n";
175 
176  response.SetStatus(HttpResponse::SC_OK);
177  response.AddHeader("Server", http_server_name);
178  response.AddHeader("MIME-Version", "1.0");
179  response.AddHeader("Content-Type", "text/html");
180  response.SetContent(content);
181 
182  return true;
183 }
184 
185 // +--------------------------------------------------------------------+
186 
187 bool
189 {
190  return DoGet(request, response);
191 }
192 
193 // +--------------------------------------------------------------------+
194 
195 bool
197 {
198  if (DoGet(request, response)) {
199  int len = response.Content().length();
200 
201  char buffer[256];
202  sprintf_s(buffer, "%d", len);
203  response.SetHeader("Content-Length", buffer);
204  response.SetContent("");
205 
206  return true;
207  }
208 
209  return false;
210 }
211 
212 // +--------------------------------------------------------------------+
213 // +--------------------------------------------------------------------+
214 // +--------------------------------------------------------------------+
215 
217  : method(0)
218 {
219  if (r && *r)
220  ParseRequest(r);
221 }
222 
224 {
225  query.destroy();
226  headers.destroy();
227  cookies.destroy();
228 }
229 
230 // +--------------------------------------------------------------------+
231 
232 void
234 {
235  if (request.length() <= 8)
236  return;
237 
238  const char* pReq = 0;
239  const char* pURI = 0;
240  const char* pQuery = 0;
241 
242  switch (request[0]) {
243  case 'G':
244  if (request.indexOf("GET") == 0)
245  method = HTTP_GET;
246  break;
247 
248  case 'P':
249  if (request.indexOf("POST") == 0)
250  method = HTTP_POST;
251  break;
252 
253  case 'H':
254  if (request.indexOf("HEAD") == 0)
255  method = HTTP_HEAD;
256  break;
257 
258  default:
259  break;
260  }
261 
262  if (!method) return;
263 
264  char buffer[1024];
265  int i = 0;
266 
267  // save the request line:
268  pReq = request.data();
269  while (*pReq && *pReq != '\n')
270  buffer[i++] = *pReq++;
271  buffer[i] = 0;
272 
273  request_line = buffer;
274  i = 0;
275 
276  // find the URI:
277  pURI = request.data();
278  while (*pURI && !isspace(*pURI))
279  pURI++;
280 
281  while (*pURI && isspace(*pURI))
282  pURI++;
283 
284  // copy the URI and find the query string:
285  while (*pURI && *pURI != '?' && !isspace(*pURI)) {
286  buffer[i++] = *pURI++;
287  }
288 
289  buffer[i] = 0;
290  uri = buffer;
291  pQuery = pURI;
292 
293  // parse the query string:
294  if (*pQuery == '?') {
295  pQuery++;
296 
297  while (*pQuery && !isspace(*pQuery)) {
298  char name_buf[1024];
299  char value_buf[1024];
300 
301  i = 0;
302  while (*pQuery && *pQuery != '=' && !isspace(*pQuery))
303  name_buf[i++] = *pQuery++;
304  name_buf[i] = 0;
305 
306  if (*pQuery == '=')
307  pQuery++;
308 
309  i = 0;
310  while (*pQuery && *pQuery != '&' && !isspace(*pQuery))
311  value_buf[i++] = *pQuery++;
312  value_buf[i] = 0;
313 
314  if (*pQuery == '&')
315  pQuery++;
316 
317  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf));
318  if (param)
319  query.append(param);
320  }
321  }
322 
323  // get the headers:
324  const char* p = request.data();
325  while (*p && *p != '\n')
326  p++;
327 
328  if (*p == '\n') p++;
329 
330  while (*p && *p != '\r' && *p != '\n') {
331  char name_buf[1024];
332  char value_buf[1024];
333 
334  i = 0;
335  while (*p && *p != ':')
336  name_buf[i++] = *p++;
337  name_buf[i] = 0;
338 
339  p++; // skip ':'
340  while (isspace(*p)) p++; // skip spaces
341 
342  i = 0;
343  while (*p && *p != '\r' && *p != '\n') // read to end of header line
344  value_buf[i++] = *p++;
345  value_buf[i] = 0;
346 
347  if (!_stricmp(name_buf, "Cookie")) {
348  ParseCookie(value_buf);
349  }
350  else {
351  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf);
352  if (param)
353  headers.append(param);
354  }
355 
356  while (*p && *p != '\n')
357  p++;
358 
359  if (*p == '\n') p++;
360  }
361 
362  if (method == HTTP_POST && *p) {
363  while (*p == '\n' || *p == '\r')
364  p++;
365 
366  content = *p;
367  pQuery = p;
368 
369  while (*pQuery && !isspace(*pQuery)) {
370  char name_buf[1024];
371  char value_buf[1024];
372 
373  i = 0;
374  while (*pQuery && *pQuery != '=' && !isspace(*pQuery))
375  name_buf[i++] = *pQuery++;
376  name_buf[i] = 0;
377 
378  if (*pQuery == '=')
379  pQuery++;
380 
381  i = 0;
382  while (*pQuery && *pQuery != '&' && !isspace(*pQuery))
383  value_buf[i++] = *pQuery++;
384  value_buf[i] = 0;
385 
386  if (*pQuery == '&')
387  pQuery++;
388 
389  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf));
390  if (param)
391  query.append(param);
392  }
393  }
394 }
395 
396 void
397 HttpRequest::ParseCookie(const char* param)
398 {
399  const char* p = param;
400 
401  while (p && *p) {
402  while (isspace(*p)) p++;
403 
404  // just ignore reserved attributes
405  if (*p == '$') {
406  while (*p && !isspace(*p) && *p != ';') p++;
407 
408  if (*p == ';')
409  p++;
410  }
411 
412  // found a cookie!
413  else if (isalpha(*p)) {
414  char name[1024];
415  char data[1024];
416 
417  char* d = name;
418  while (*p && *p != '=')
419  *d++ = *p++;
420  *d = 0;
421 
422  if (*p == '=')
423  p++;
424 
425  if (*p == '"')
426  p++;
427 
428  d = data;
429  while (*p && *p != '"' && *p != ';')
430  *d++ = *p++;
431  *d = 0;
432 
433  if (*p == '"')
434  p++;
435 
436  if (*p == ';')
437  p++;
438 
439  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data);
440  if (param)
441  cookies.append(param);
442  }
443 
444  // this shouldn't happen - abandon the parse
445  else {
446  return;
447  }
448  }
449 }
450 
451 // +--------------------------------------------------------------------+
452 
453 Text
454 HttpRequest::GetParam(const char* name)
455 {
456  ListIter<HttpParam> iter = query;
457  while (++iter) {
458  HttpParam* p = iter.value();
459 
460  if (p->name == name)
461  return p->value;
462  }
463 
464  return Text();
465 }
466 
467 // +--------------------------------------------------------------------+
468 
469 Text
470 HttpRequest::GetHeader(const char* name)
471 {
472  ListIter<HttpParam> iter = headers;
473  while (++iter) {
474  HttpParam* p = iter.value();
475 
476  if (p->name == name)
477  return p->value;
478  }
479 
480  return Text();
481 }
482 
483 void
484 HttpRequest::SetHeader(const char* name, const char* value)
485 {
486  ListIter<HttpParam> iter = headers;
487  while (++iter) {
488  HttpParam* p = iter.value();
489 
490  if (p->name == name) {
491  p->value = value;
492  return;
493  }
494  }
495 
496  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
497  if (param)
498  headers.append(param);
499 }
500 
501 void
502 HttpRequest::AddHeader(const char* name, const char* value)
503 {
504  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
505  if (param)
506  headers.append(param);
507 }
508 
509 // +--------------------------------------------------------------------+
510 
511 Text
512 HttpRequest::GetCookie(const char* name)
513 {
514  ListIter<HttpParam> iter = cookies;
515  while (++iter) {
516  HttpParam* p = iter.value();
517 
518  if (p->name == name)
519  return p->value;
520  }
521 
522  return Text();
523 }
524 
525 void
526 HttpRequest::SetCookie(const char* name, const char* value)
527 {
528  ListIter<HttpParam> iter = cookies;
529  while (++iter) {
530  HttpParam* p = iter.value();
531 
532  if (p->name == name) {
533  p->value = value;
534  return;
535  }
536  }
537 
538  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
539  if (param)
540  cookies.append(param);
541 }
542 
543 void
544 HttpRequest::AddCookie(const char* name, const char* value)
545 {
546  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
547  if (param)
548  cookies.append(param);
549 }
550 
551 // +--------------------------------------------------------------------+
552 
553 Text
554 HttpRequest::DecodeParam(const char* value)
555 {
556  if (!value || !*value) return "";
557 
558  int size = strlen(value);
559  char val = 0;
560  char code[4];
561  char sbuf[256];
562  char* lbuf = 0;
563 
564  char* dst = sbuf;
565  char* p = sbuf;
566 
567  if (size > 255) {
568  lbuf = new(__FILE__,__LINE__) char[size+1];
569  dst = lbuf;
570  p = lbuf;
571  }
572 
573  if (p) {
574  while (*value) {
575  switch (*value) {
576  default: *p++ = *value; break;
577  case '+': *p++ = ' '; break;
578 
579  case '%':
580  value++;
581  code[0] = *value++;
582  code[1] = *value;
583  code[2] = 0;
584 
585  val = (char) strtol(code, 0, 16);
586  *p++ = val;
587  break;
588  }
589 
590  value++;
591  }
592 
593  *p = 0;
594  }
595 
596  Text result = dst;
597 
598  if (lbuf)
599  delete [] lbuf;
600 
601  return result;
602 }
603 
604 // +--------------------------------------------------------------------+
605 
606 Text
607 HttpRequest::EncodeParam(const char* value)
608 {
609  if (!value || !*value) return "";
610 
611  int size = strlen(value);
612  char hex1 = 0;
613  char hex2 = 0;
614 
615  char sbuf[1024];
616  char* lbuf = 0;
617 
618  char* dst = sbuf;
619  char* p = sbuf;
620 
621  if (size > 255) {
622  lbuf = new(__FILE__,__LINE__) char[4*size+1];
623  dst = lbuf;
624  p = lbuf;
625  }
626 
627  if (p) {
628  while (*value) {
629  switch (*value) {
630  default: *p++ = *value; break;
631  case ' ': *p++ = '+'; break;
632 
633  case '?': *p++ = '%'; *p++ = '3'; *p++ = 'F'; break;
634  case '&': *p++ = '%'; *p++ = '2'; *p++ = '6'; break;
635  case ':': *p++ = '%'; *p++ = '3'; *p++ = 'A'; break;
636  case '/': *p++ = '%'; *p++ = '2'; *p++ = 'F'; break;
637  case '\\': *p++ = '%'; *p++ = '5'; *p++ = 'C'; break;
638  case '%': *p++ = '%'; *p++ = '2'; *p++ = '5'; break;
639  case '|': *p++ = '%'; *p++ = '7'; *p++ = 'C'; break;
640  case '<': *p++ = '%'; *p++ = '3'; *p++ = 'C'; break;
641  case '>': *p++ = '%'; *p++ = '3'; *p++ = 'E'; break;
642  case '[': *p++ = '%'; *p++ = '5'; *p++ = 'B'; break;
643  case ']': *p++ = '%'; *p++ = '5'; *p++ = 'D'; break;
644  case '{': *p++ = '%'; *p++ = '7'; *p++ = 'B'; break;
645  case '}': *p++ = '%'; *p++ = '7'; *p++ = 'D'; break;
646  case '"': *p++ = '%'; *p++ = '2'; *p++ = '2'; break;
647  case '^': *p++ = '%'; *p++ = '5'; *p++ = 'E'; break;
648  case '`': *p++ = '%'; *p++ = '6'; *p++ = '0'; break;
649  case '\n': break;
650  case '\r': break;
651  case '\t': break;
652  }
653 
654  value++;
655  }
656 
657  *p = 0;
658  }
659 
660  Text result = dst;
661 
662  if (lbuf)
663  delete [] lbuf;
664 
665  return result;
666 }
667 
668 // +--------------------------------------------------------------------+
669 
670 HttpRequest::operator Text()
671 {
672  Text response = request_line.data();
673  response += "\n";
674 
675  for (int i = 0; i < headers.size(); i++) {
676  HttpParam* h = headers[i];
677  response += h->name;
678  response += ": ";
679  response += h->value;
680  response += "\n";
681  }
682 
683  for (int i = 0; i < cookies.size(); i++) {
684  HttpParam* c = cookies[i];
685  response += "Cookie: ";
686  response += c->name;
687  response += "=\"";
688  response += c->value;
689  response += "\"\n";
690  }
691 
692  response += "Connection: close\n\n";
693  response += content;
694 
695  return response;
696 }
697 
698 // +--------------------------------------------------------------------+
699 // +--------------------------------------------------------------------+
700 // +--------------------------------------------------------------------+
701 
702 HttpResponse::HttpResponse(int stat, const char* data)
703  : status(stat), content(data)
704 { }
705 
707  : status(0), content(r)
708 {
709  if (r && *r)
710  ParseResponse(r);
711 }
712 
714 {
715  headers.destroy();
716  cookies.destroy();
717 }
718 
719 // +--------------------------------------------------------------------+
720 
721 HttpResponse::operator Text()
722 {
723  Text response;
724 
725  switch (status) {
726  case SC_CONTINUE : response = "HTTP/1.1 100 Continue\n"; break;
727  case SC_SWITCHING_PROTOCOLS : response = "HTTP/1.1 101 Switching Protocols\n"; break;
728 
729  case SC_OK : response = "HTTP/1.1 200 OK\n"; break;
730  case SC_CREATED : response = "HTTP/1.1 201 Created\n"; break;
731  case SC_ACCEPTED : response = "HTTP/1.1 202 Accepted\n"; break;
732  case SC_NON_AUTHORITATIVE : response = "HTTP/1.1 203 Non Authoritative\n"; break;
733  case SC_NO_CONTENT : response = "HTTP/1.1 204 No Content\n"; break;
734  case SC_RESET_CONTENT : response = "HTTP/1.1 205 Reset Content\n"; break;
735  case SC_PARTIAL_CONTENT : response = "HTTP/1.1 206 Partial Content\n"; break;
736 
737  case SC_MULTIPLE_CHOICES : response = "HTTP/1.1 300 Multiple Choices\n"; break;
738  case SC_MOVED_PERMANENTLY : response = "HTTP/1.1 301 Moved Permanently\n"; break;
739  case SC_FOUND : response = "HTTP/1.1 302 Found\n"; break;
740  case SC_SEE_OTHER : response = "HTTP/1.1 303 See Other\n"; break;
741  case SC_NOT_MODIFIED : response = "HTTP/1.1 304 Not Modified\n"; break;
742  case SC_USE_PROXY : response = "HTTP/1.1 305 Use Proxy\n"; break;
743  case SC_TEMPORARY_REDIRECT : response = "HTTP/1.1 307 Temporary Redirect\n"; break;
744 
745  case SC_BAD_REQUEST : response = "HTTP/1.1 400 Bad Request\n"; break;
746  case SC_UNAUTHORIZED : response = "HTTP/1.1 401 Unauthorized\n"; break;
747  case SC_PAYMENT_REQUIRED : response = "HTTP/1.1 402 Payment Required\n"; break;
748  case SC_FORBIDDEN : response = "HTTP/1.1 403 Forbidden\n"; break;
749  case SC_NOT_FOUND : response = "HTTP/1.1 404 Not Found\n"; break;
750  case SC_METHOD_NOT_ALLOWED : response = "HTTP/1.1 405 Method Not Allowed\n"; break;
751  case SC_NOT_ACCEPTABLE : response = "HTTP/1.1 406 Not Acceptable\n"; break;
752  case SC_PROXY_AUTH_REQ : response = "HTTP/1.1 407 Proxy Authorization Req\n"; break;
753  case SC_REQUEST_TIME_OUT : response = "HTTP/1.1 408 Request Timeout\n"; break;
754  case SC_CONFLICT : response = "HTTP/1.1 409 Conflict\n"; break;
755  case SC_GONE : response = "HTTP/1.1 410 Gone\n"; break;
756  case SC_LENGTH_REQUIRED : response = "HTTP/1.1 411 Length Required\n"; break;
757 
758  default:
759  case SC_SERVER_ERROR : response = "HTTP/1.1 500 Internal Server Error\n"; break;
760  case SC_NOT_IMPLEMENTED : response = "HTTP/1.1 501 Not Implemented\n"; break;
761  case SC_BAD_GATEWAY : response = "HTTP/1.1 502 Bad Gateway\n"; break;
762  case SC_SERVICE_UNAVAILABLE : response = "HTTP/1.1 503 Service Unavailable\n"; break;
763  case SC_GATEWAY_TIMEOUT : response = "HTTP/1.1 504 Gateway Timeout\n"; break;
764  case SC_VERSION_NOT_SUPPORTED: response = "HTTP/1.1 505 HTTP Version Not Supported\n"; break;
765  }
766 
767  SetHeader("Connection", "close");
768 
769  char buffer[256];
770 
771  if (content.length()) {
772  sprintf_s(buffer, "%d", content.length());
773  SetHeader("Content-Length", buffer);
774  }
775 
776  for (int i = 0; i < cookies.size(); i++) {
777  HttpParam* cookie = cookies.at(i);
778  sprintf_s(buffer, "%s=\"%s\"; Version=\"1\"", cookie->name.data(), cookie->value.data());
779 
780  AddHeader("Set-Cookie", buffer);
781  }
782 
783  for (int i = 0; i < headers.size(); i++) {
784  const HttpParam* p = headers.at(i);
785  sprintf_s(buffer, "%s: %s\n", p->name.data(), p->value.data());
786  response += buffer;
787  }
788 
789  response += "\n";
790  response += content;
791 
792  return response;
793 }
794 
795 // +--------------------------------------------------------------------+
796 
797 Text
798 HttpResponse::GetHeader(const char* name)
799 {
800  ListIter<HttpParam> iter = headers;
801  while (++iter) {
802  HttpParam* p = iter.value();
803 
804  if (p->name == name)
805  return p->value;
806  }
807 
808  return Text();
809 }
810 
811 void
812 HttpResponse::SetHeader(const char* name, const char* value)
813 {
814  ListIter<HttpParam> iter = headers;
815  while (++iter) {
816  HttpParam* p = iter.value();
817 
818  if (p->name == name) {
819  p->value = value;
820  return;
821  }
822  }
823 
824  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
825  if (param)
826  headers.append(param);
827 }
828 
829 void
830 HttpResponse::AddHeader(const char* name, const char* value)
831 {
832  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
833  if (param)
834  headers.append(param);
835 }
836 
837 // +--------------------------------------------------------------------+
838 
839 Text
840 HttpResponse::GetCookie(const char* name)
841 {
842  ListIter<HttpParam> iter = cookies;
843  while (++iter) {
844  HttpParam* p = iter.value();
845 
846  if (p->name == name)
847  return p->value;
848  }
849 
850  return Text();
851 }
852 
853 void
854 HttpResponse::SetCookie(const char* name, const char* value)
855 {
856  ListIter<HttpParam> iter = cookies;
857  while (++iter) {
858  HttpParam* p = iter.value();
859 
860  if (p->name == name) {
861  p->value = value;
862  return;
863  }
864  }
865 
866  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
867  if (param)
868  cookies.append(param);
869 }
870 
871 void
872 HttpResponse::AddCookie(const char* name, const char* value)
873 {
874  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
875  if (param)
876  cookies.append(param);
877 }
878 
879 // +--------------------------------------------------------------------+
880 
881 void
883 {
884  status = SC_TEMPORARY_REDIRECT;
885  SetHeader("Location", url);
886 }
887 
888 // +--------------------------------------------------------------------+
889 
890 void
892 {
893  if (response.length() <= 12 || response.indexOf("HTTP/1.") != 0)
894  return;
895 
896  const char* pStatus = response.data() + 9;
897 
898  sscanf_s(pStatus, "%d", &status);
899  if (!status) return;
900 
901  int i = 0;
902 
903  // get the headers:
904  const char* p = response.data();
905  while (*p && *p != '\n')
906  p++;
907 
908  if (*p == '\n') p++;
909 
910  while (*p && *p != '\r' && *p != '\n') {
911  char name_buf[1024];
912  char value_buf[1024];
913 
914  i = 0;
915  while (*p && *p != ':')
916  name_buf[i++] = *p++;
917  name_buf[i] = 0;
918 
919  p++; // skip ':'
920  while (isspace(*p)) p++; // skip spaces
921 
922  i = 0;
923  while (*p && *p != '\r' && *p != '\n') // read to end of header line
924  value_buf[i++] = *p++;
925  value_buf[i] = 0;
926 
927  if (!_stricmp(name_buf, "Set-Cookie")) {
928  ParseCookie(value_buf);
929  }
930  else {
931  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf);
932  if (param)
933  headers.append(param);
934  }
935 
936  while (*p && *p != '\n')
937  p++;
938 
939  if (*p == '\n') p++;
940  }
941 
942  if (*p == '\n') p++;
943  content = p;
944 }
945 
946 void
947 HttpResponse::ParseCookie(const char* param)
948 {
949  const char* p = param;
950 
951  while (p && *p) {
952  while (isspace(*p)) p++;
953 
954  // just ignore reserved attributes
955  if (*p == '$') {
956  while (*p && !isspace(*p) && *p != ';') p++;
957 
958  if (*p == ';')
959  p++;
960  }
961 
962  // found a cookie!
963  else if (isalpha(*p)) {
964  char name[1024];
965  char data[1024];
966 
967  char* d = name;
968  while (*p && *p != '=')
969  *d++ = *p++;
970  *d = 0;
971 
972  if (*p == '=')
973  p++;
974 
975  if (*p == '"')
976  p++;
977 
978  d = data;
979  while (*p && *p != '"' && *p != ';')
980  *d++ = *p++;
981  *d = 0;
982 
983  if (*p == '"')
984  p++;
985 
986  if (*p == ';')
987  p++;
988 
989  // ignore the version attribute
990  if (_stricmp(name, "version")) {
991  HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data);
992  if (param)
993  cookies.append(param);
994  }
995  }
996 
997  // this shouldn't happen - abandon the parse
998  else {
999  return;
1000  }
1001  }
1002 }
1003