00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CSConfig.h"
00028
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <inttypes.h>
00032
00033 #include "CSGlobal.h"
00034 #include "CSHTTPStream.h"
00035 #include "CSLog.h"
00036
00037 #ifdef DEBUG
00038
00039 #endif
00040
00041
00042
00043
00044
00045
00046 CSHeader::~CSHeader()
00047 {
00048 if (iName) {
00049 iName->release();
00050 iName = NULL;
00051 }
00052 if (iValue) {
00053 iValue->release();
00054 iValue = NULL;
00055 }
00056 }
00057
00058 void CSHeader::setName(const char *name)
00059 {
00060 iName = CSString::newString(name);
00061 }
00062
00063 void CSHeader::setName(const char *name, uint32_t len)
00064 {
00065 iName = CSString::newString(name, len);
00066 }
00067
00068 void CSHeader::setName(CSString *name)
00069 {
00070 iName = name;
00071 }
00072
00073 void CSHeader::setValue(const char *value)
00074 {
00075 iValue = CSString::newString(value);
00076 }
00077
00078 void CSHeader::setValue(const char *value, uint32_t len)
00079 {
00080 iValue = CSString::newString(value, len);
00081 }
00082
00083 void CSHeader::setValue(CSString *value)
00084 {
00085 iValue = value;
00086 }
00087
00088 void CSHeader::write(CSOutputStream *out, bool trace)
00089 {
00090 if (trace)
00091 printf("%s: %s\n", iName->getCString(), iValue->getCString());
00092
00093 out->print(iName);
00094 out->print(": ");
00095 if (iValue)
00096 out->print(iValue);
00097 out->print("\r\n");
00098 }
00099
00100 void CSHTTPHeaders::clearHeaders()
00101 {
00102 iKeepAlive = false;
00103 iExpect100Continue = false;
00104 iUnknownEpectHeader = false;
00105 if (iHeaders) {
00106 iHeaders->release();
00107 iHeaders = NULL;
00108 }
00109 }
00110 CSVector *CSHTTPHeaders::takeHeaders()
00111 {
00112 CSVector *headers = iHeaders;
00113 iHeaders = NULL;
00114 return headers;
00115 }
00116
00117 void CSHTTPHeaders::setHeaders(CSVector *headers)
00118 {
00119 if (iHeaders)
00120 iHeaders->release();
00121 iHeaders = headers;
00122 }
00123
00124 void CSHTTPHeaders::addHeader(CSHeader *h)
00125 {
00126 if (!iHeaders)
00127 new_(iHeaders, CSVector(5));
00128
00129 if (strcasecmp(h->getNameCString(), "Connection") == 0 && strcasecmp(h->getValueCString(), "Keep-Alive") == 0)
00130 iKeepAlive = true;
00131
00132 if (strcasecmp(h->getNameCString(), "Expect") == 0) {
00133 if (strcasecmp(h->getValueCString(), "100-continue") == 0)
00134 iExpect100Continue = true;
00135 else
00136 iUnknownEpectHeader = true;
00137 }
00138
00139 iHeaders->add(h);
00140 }
00141
00142 void CSHTTPHeaders::addHeaders(CSHTTPHeaders *headers)
00143 {
00144 CSHeader *h;
00145 uint32_t i =0;
00146 while ((h = headers->getHeader(i++))) {
00147 addHeader(h);
00148 }
00149 }
00150
00151 void CSHTTPHeaders::addHeader(const char *name, const char *value)
00152 {
00153 CSHeader *h;
00154
00155 enter_();
00156 if (!iHeaders)
00157 new_(iHeaders, CSVector(5));
00158
00159 new_(h, CSHeader());
00160 push_(h);
00161 h->setName(name);
00162 h->setValue(value);
00163 pop_(h);
00164
00165 addHeader(h);
00166 exit_();
00167 }
00168
00169 void CSHTTPHeaders::addHeader(const char *name, uint32_t nlen, const char *value, uint32_t vlen)
00170 {
00171 CSHeader *h;
00172
00173 enter_();
00174 if (!iHeaders)
00175 new_(iHeaders, CSVector(5));
00176
00177 new_(h, CSHeader());
00178 push_(h);
00179 h->setName(name, nlen);
00180 h->setValue(value, vlen);
00181 pop_(h);
00182 addHeader(h);
00183 exit_();
00184 }
00185
00186 void CSHTTPHeaders::addHeader(CSString *name, CSString *value)
00187 {
00188 CSHeader *h;
00189
00190 enter_();
00191 push_(name);
00192 push_(value);
00193 if (!iHeaders)
00194 new_(iHeaders, CSVector(5));
00195
00196 new_(h, CSHeader());
00197 pop_(value);
00198 pop_(name);
00199 h->setName(name);
00200 h->setValue(value);
00201 addHeader(h);
00202 exit_();
00203 }
00204
00205 void CSHTTPHeaders::addHeader(const char *name, CSString *value)
00206 {
00207 CSHeader *h;
00208 CSString *n;
00209
00210 enter_();
00211 push_(value);
00212 n = CSString::newString(name);
00213 push_(n);
00214 if (!iHeaders)
00215 new_(iHeaders, CSVector(5));
00216 new_(h, CSHeader());
00217 pop_(n);
00218 pop_(value);
00219 h->setName(n);
00220 h->setValue(value);
00221 addHeader(h);
00222 exit_();
00223 }
00224
00225 void CSHTTPHeaders::addHeader(const char *name, uint64_t value)
00226 {
00227 char buffer[30];
00228
00229 snprintf(buffer, 30, "%"PRIu64, value);
00230 addHeader(name, buffer);
00231 }
00232
00233 void CSHTTPHeaders::removeHeader(CSString *name)
00234 {
00235 enter_();
00236 push_(name);
00237 if (iHeaders) {
00238 CSHeader *h;
00239
00240 for (uint32_t i=0; i<iHeaders->size(); ) {
00241 h = (CSHeader *) iHeaders->get(i);
00242 if (h->getName()->compare(name) == 0) {
00243 iHeaders->remove(i);
00244 } else
00245 i++;
00246 }
00247 }
00248 release_(name);
00249
00250 exit_();
00251 }
00252
00253 void CSHTTPHeaders::removeHeader(const char *name)
00254 {
00255 removeHeader(CSString::newString(name));
00256 }
00257
00258 CSString *CSHTTPHeaders::getHeaderValue(const char *name)
00259 {
00260 CSString *v;
00261
00262 v = NULL;
00263 if (iHeaders) {
00264 CSHeader *h;
00265
00266 for (uint32_t i=0; i<iHeaders->size(); i++) {
00267 h = (CSHeader *) iHeaders->get(i);
00268 if (h->getName()->compare(name) == 0) {
00269 v = h->getValue();
00270 v->retain();
00271 break;
00272 }
00273 }
00274 }
00275 return v;
00276 }
00277
00278 const char *CSHTTPHeaders::getHeaderCStringValue(const char *name)
00279 {
00280 if (iHeaders) {
00281 CSHeader *h;
00282
00283 for (uint32_t i=0; i<iHeaders->size(); i++) {
00284 h = (CSHeader *) iHeaders->get(i);
00285 if (h->getName()->compare(name) == 0) {
00286 return h->getValue()->getCString();
00287 }
00288 }
00289 }
00290 return NULL;
00291 }
00292
00293 void CSHTTPHeaders::writeHeader(CSOutputStream *out, bool trace)
00294 {
00295 if (iHeaders) {
00296 CSHeader *h;
00297
00298 for (uint32_t i=0; i<iHeaders->size(); i++) {
00299 h = (CSHeader *) iHeaders->get(i);
00300 h->write(out, trace);
00301 }
00302 }
00303 }
00304
00305 bool CSHTTPHeaders::keepAlive()
00306 {
00307 return iKeepAlive;
00308 }
00309
00310 bool CSHTTPHeaders::expect100Continue()
00311 {
00312 return iExpect100Continue;
00313 }
00314
00315 bool CSHTTPHeaders::unknownEpectHeader()
00316 {
00317 return iUnknownEpectHeader;
00318 }
00319
00320
00321
00322
00323
00324
00325 CSHTTPInputStream::CSHTTPInputStream(CSInputStream* in):
00326 CSHTTPHeaders(),
00327 iInput(NULL),
00328 iMethod(NULL),
00329 iRequestURI(NULL),
00330 iHTTPVersion(NULL),
00331 iStatusPhrase(NULL)
00332 {
00333 iInput = in;
00334 }
00335
00336 CSHTTPInputStream::~CSHTTPInputStream()
00337 {
00338 freeHead();
00339 if (iInput)
00340 iInput->release();
00341 }
00342
00343 void CSHTTPInputStream::readHead(bool trace)
00344 {
00345 CSStringBuffer *sb = NULL;
00346 bool first_line = true;
00347 uint32_t start, end;
00348
00349 enter_();
00350 freeHead();
00351 for (;;) {
00352 sb = iInput->readLine();
00353 if (!sb)
00354 break;
00355 if (trace) {
00356 if (first_line)
00357 CSL.log(self, CSLog::Protocol, "HTTP Request - Header:\n");
00358 printf("%s\n", sb->getCString());
00359 }
00360 if (sb->length() == 0) {
00361 sb->release();
00362 break;
00363 }
00364 push_(sb);
00365
00366 if (first_line) {
00367 CSString *str;
00368 start = sb->ignore(0, ' ');
00369 end = sb->find(start, ' ');
00370 str = sb->substr(start, end - start);
00371 if (str->startsWith("HTTP")) {
00372 iMethod = NULL;
00373 iRequestURI = NULL;
00374 iHTTPVersion = str;
00375 start = sb->ignore(end, ' ');
00376 end = sb->find(start, ' ');
00377 if (start > end)
00378 CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
00379
00380 str = sb->substr(start, end - start);
00381 iStatus = atol(str->getCString());
00382 str->release();
00383 start = sb->ignore(end, ' ');
00384 end = sb->find(start, '\r');
00385 if (start > end)
00386 CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
00387 iStatusPhrase = sb->substr(start, end - start);
00388 } else {
00389 iStatus = 0;
00390 iStatusPhrase = NULL;
00391 iMethod = str;
00392 start = sb->ignore(end, ' ');
00393 end = sb->find(start, ' ');
00394 if (start > end)
00395 CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
00396 iRequestURI = sb->substr(start, end - start);
00397 start = sb->ignore(end, ' ');
00398 end = sb->find(start, ' ');
00399 if (start > end)
00400 CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
00401 iHTTPVersion = sb->substr(start, end - start);
00402 }
00403 first_line = false;
00404 }
00405 else {
00406 uint32_t nstart, nend;
00407 uint32_t vstart, vend;
00408
00409 nstart = sb->ignore(0, ' ');
00410 nend = sb->find(nstart, ':');
00411
00412 vstart = sb->ignore(nend+1, ' ');
00413 vend = sb->find(vstart, '\r');
00414
00415 nend = sb->trim(nend, ' ');
00416 vend = sb->trim(vend, ' ');
00417
00418 if (vstart > vend)
00419 CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
00420 addHeader(sb->getBuffer(nstart), nend-nstart, sb->getBuffer(vstart), vend-vstart);
00421 }
00422
00423 release_(sb);
00424 }
00425 exit_();
00426 }
00427
00428 void CSHTTPInputStream::readBody()
00429 {
00430 uint64_t body_size;
00431 size_t tfer, len;
00432
00433 if (getContentLength(&body_size)) {
00434 iBody.setLength((size_t) body_size);
00435 len = 0;
00436 while (len < body_size) {
00437 tfer = read(iBody.getBuffer(len), (size_t)(body_size - len));
00438 if (!tfer)
00439 CSException::throwException(CS_CONTEXT, CS_ERR_BODY_INCOMPLETE, "POST data incomplete");
00440 len += tfer;
00441 }
00442 }
00443 else {
00444 CSStringBuffer *sb = NULL;
00445
00446
00447 for (;;) {
00448 sb = readLine();
00449 if (!sb)
00450 break;
00451 if (sb->length() == 0) {
00452 sb->release();
00453 break;
00454 }
00455 iBody.append(sb->getBuffer(0), sb->length());
00456 iBody.append((char) '\n');
00457 sb->release();
00458 }
00459 }
00460 }
00461
00462 bool CSHTTPInputStream::getRange(uint64_t *size, uint64_t *offset)
00463 {
00464 CSString *val;
00465 bool haveRange = false;
00466
00467 if ((val = getHeaderValue("Range"))) {
00468 uint64_t first_byte = 0, last_byte = 0;
00469 const char *range = val->getCString();
00470
00471 if (range && (val->compare("bytes=", 6) == 0)) {
00472 if ((sscanf(range + 6, "%"PRIu64"-%"PRIu64"", &first_byte, &last_byte) == 2) && (last_byte >= first_byte)) {
00473 *offset = (uint64_t) first_byte;
00474 *size =last_byte - first_byte + 1;
00475 haveRange = true;
00476 }
00477 }
00478 val->release();
00479
00480 }
00481 return haveRange;
00482 }
00483
00484 bool CSHTTPInputStream::getContentLength(uint64_t *length)
00485 {
00486 CSString *val;
00487 uint64_t size = 0;
00488
00489 if ((val = getHeaderValue("Content-Length"))) {
00490 const char *len = val->getCString();
00491
00492 if (len)
00493 sscanf(len, "%"PRIu64"", &size);
00494 val->release();
00495 *length = size;
00496 return true;
00497 }
00498 return false;
00499 }
00500
00501 const char *CSHTTPInputStream::getMethod()
00502 {
00503 if (!iMethod)
00504 return NULL;
00505 return iMethod->getCString();
00506 }
00507
00508 void CSHTTPInputStream::close()
00509 {
00510 enter_();
00511 iInput->close();
00512 exit_();
00513 }
00514
00515 size_t CSHTTPInputStream::read(char *b, size_t len)
00516 {
00517 enter_();
00518 return_(iInput->read(b, len));
00519 }
00520
00521 int CSHTTPInputStream::read()
00522 {
00523 enter_();
00524 return_(iInput->read());
00525 }
00526
00527 int CSHTTPInputStream::peek()
00528 {
00529 enter_();
00530 return_(iInput->peek());
00531 }
00532
00533 void CSHTTPInputStream::freeHead()
00534 {
00535 enter_();
00536 clearHeaders();
00537 if (iMethod) {
00538 iMethod->release();
00539 iMethod = NULL;
00540 }
00541 if (iRequestURI) {
00542 iRequestURI->release();
00543 iRequestURI = NULL;
00544 }
00545 if (iHTTPVersion) {
00546 iHTTPVersion->release();
00547 iHTTPVersion = NULL;
00548 }
00549 if (iStatusPhrase) {
00550 iStatusPhrase->release();
00551 iStatusPhrase = NULL;
00552 }
00553 iStatus = 0;
00554 exit_();
00555 }
00556
00557 CSHTTPInputStream *CSHTTPInputStream::newStream(CSInputStream* i)
00558 {
00559 CSHTTPInputStream *s;
00560
00561 if (!(s = new CSHTTPInputStream(i))) {
00562 i->release();
00563 CSException::throwOSError(CS_CONTEXT, ENOMEM);
00564 }
00565 return s;
00566 }
00567
00568
00569
00570
00571
00572
00573 CSHTTPOutputStream::CSHTTPOutputStream(CSOutputStream* out):
00574 CSHTTPHeaders(),
00575 iOutput(NULL),
00576 iStatus(0),
00577 iContentLength(0),
00578 iRangeSize(0),
00579 iRangeOffset(0),
00580 iTotalLength(0)
00581 {
00582 iOutput = out;
00583 iBody.setGrowSize(120);
00584 }
00585
00586 CSHTTPOutputStream::~CSHTTPOutputStream()
00587 {
00588 clearHeaders();
00589 clearBody();
00590 if (iOutput)
00591 iOutput->release();
00592 }
00593
00594 void CSHTTPOutputStream::print(const char *str, bool trace)
00595 {
00596 if (trace)
00597 printf("%s", str);
00598 iOutput->print(str);
00599 }
00600
00601
00602 void CSHTTPOutputStream::print(int32_t value, bool trace)
00603 {
00604 if (trace)
00605 printf("%d", value);
00606 iOutput->print(value);
00607 }
00608
00609 void CSHTTPOutputStream::print(uint64_t value, bool trace)
00610 {
00611 if (trace)
00612 printf("%"PRIu64, value);
00613 iOutput->print(value);
00614 }
00615
00616 void CSHTTPOutputStream::writeHeaders(bool trace)
00617 {
00618 writeHeader(this, trace);
00619 clearHeaders();
00620 }
00621
00622 void CSHTTPOutputStream::writeHead(bool trace)
00623 {
00624 enter_();
00625 if (trace)
00626 CSL.log(self, CSLog::Protocol, "HTTP Reply - Header:\n");
00627 print("HTTP/1.1 ", trace);
00628 print(iStatus, trace);
00629 print(" ", trace);
00630 print(getReasonPhrase(iStatus), trace);
00631 print("\r\n", trace);
00632 writeHeader(iOutput, trace);
00633 print("Content-Length: ", trace);
00634 print(iContentLength, trace);
00635 print("\r\n", trace);
00636 if (iRangeSize && (iStatus == 200)) {
00637 print("Content-Range: bytes ", trace);
00638 print(iRangeOffset, trace);
00639 print("-", trace);
00640 print(iRangeOffset + iRangeSize -1, trace);
00641 print("/", trace);
00642 print(iTotalLength, trace);
00643 print("\r\n", trace);
00644 }
00645 print("\r\n", trace);
00646 exit_();
00647
00648 }
00649
00650 void CSHTTPOutputStream::clearBody()
00651 {
00652 iRangeSize = 0;
00653 iRangeOffset = 0;
00654 iTotalLength = 0;
00655 iContentLength = 0;
00656 iBody.clear();
00657 }
00658
00659 void CSHTTPOutputStream::writeBody()
00660 {
00661 iOutput->write(iBody.getBuffer(0), iBody.length());
00662 }
00663
00664 void CSHTTPOutputStream::appendBody(const char *str)
00665 {
00666 iBody.append(str);
00667 iContentLength = iBody.length();
00668 }
00669
00670 void CSHTTPOutputStream::appendBody(int32_t value)
00671 {
00672 iBody.append(value);
00673 iContentLength = iBody.length();
00674 }
00675
00676 void CSHTTPOutputStream::appendBody(uint32_t value)
00677 {
00678 iBody.append(value);
00679 iContentLength = iBody.length();
00680 }
00681
00682 void CSHTTPOutputStream::appendBody(uint64_t value)
00683 {
00684 iBody.append(value);
00685 iContentLength = iBody.length();
00686 }
00687
00688 const char *CSHTTPOutputStream::getBodyData()
00689 {
00690 return iBody.getCString();
00691 }
00692
00693 size_t CSHTTPOutputStream::getBodyLength()
00694 {
00695 return iBody.length();
00696 }
00697
00698 void CSHTTPOutputStream::setBody(CSStringBufferImpl *buf)
00699 {
00700 iBody.take(buf);
00701 iContentLength = iBody.length();
00702 }
00703
00704 void CSHTTPOutputStream::close()
00705 {
00706 enter_();
00707 iOutput->close();
00708 exit_();
00709 }
00710
00711 void CSHTTPOutputStream::write(const char *b, size_t len)
00712 {
00713 enter_();
00714 iOutput->write(b, len);
00715 exit_();
00716 }
00717
00718 void CSHTTPOutputStream::flush()
00719 {
00720 enter_();
00721 iOutput->flush();
00722 exit_();
00723 }
00724
00725 void CSHTTPOutputStream::write(char b)
00726 {
00727 enter_();
00728 iOutput->write(b);
00729 exit_();
00730 }
00731
00732 const char *CSHTTPOutputStream::getReasonPhrase(int code)
00733 {
00734 const char *message = "Unknown Code";
00735
00736 switch (code) {
00737 case 100: message = "Continue"; break;
00738 case 101: message = "Switching Protocols"; break;
00739 case 200: message = "OK"; break;
00740 case 201: message = "Created"; break;
00741 case 202: message = "Accepted"; break;
00742 case 203: message = "Non-Authoritative Information"; break;
00743 case 204: message = "No Content"; break;
00744 case 205: message = "Reset Content"; break;
00745 case 206: message = "Partial Content"; break;
00746 case 300: message = "Multiple Choices"; break;
00747 case 301: message = "Moved Permanently"; break;
00748 case 302: message = "Found"; break;
00749 case 303: message = "See Other"; break;
00750 case 304: message = "Not Modified"; break;
00751 case 305: message = "Use Proxy"; break;
00752 case 307: message = "Temporary Redirect"; break;
00753 case 400: message = "Bad Request"; break;
00754 case 401: message = "Unauthorized"; break;
00755 case 402: message = "Payment Required"; break;
00756 case 403: message = "Forbidden"; break;
00757 case 404: message = "Not Found"; break;
00758 case 405: message = "Method Not Allowed"; break;
00759 case 406: message = "Not Acceptable"; break;
00760 case 407: message = "Proxy Authentication Required"; break;
00761 case 408: message = "Request Time-out"; break;
00762 case 409: message = "Conflict"; break;
00763 case 410: message = "Gone"; break;
00764 case 411: message = "Length Required"; break;
00765 case 412: message = "Precondition Failed"; break;
00766 case 413: message = "Request Entity Too Large"; break;
00767 case 414: message = "Request-URI Too Large"; break;
00768 case 415: message = "Unsupported Media Type"; break;
00769 case 416: message = "Requested range not satisfiable"; break;
00770 case 417: message = "Expectation Failed"; break;
00771 case 500: message = "Internal Server Error"; break;
00772 case 501: message = "Not Implemented"; break;
00773 case 502: message = "Bad Gateway"; break;
00774 case 503: message = "Service Unavailable"; break;
00775 case 504: message = "Gateway Time-out"; break;
00776 case 505: message = "HTTP Version not supported"; break;
00777 }
00778 return message;
00779 }
00780
00781 CSHTTPOutputStream *CSHTTPOutputStream::newStream(CSOutputStream* i)
00782 {
00783 CSHTTPOutputStream *s;
00784
00785 if (!(s = new CSHTTPOutputStream(i))) {
00786 i->release();
00787 CSException::throwOSError(CS_CONTEXT, ENOMEM);
00788 }
00789 return s;
00790 }
00791
00792