1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* Original author: Paul McCullagh (H&G2JCtL)
20
* Continued development: Barry Leslie
24
* A basic syncronized object.
34
#include "CSHTTPStream.h"
38
//#define PRINT_HEADER
42
* ---------------------------------------------------------------
58
void CSHeader::setName(const char *name)
60
iName = CSString::newString(name);
63
void CSHeader::setName(const char *name, uint32_t len)
65
iName = CSString::newString(name, len);
68
void CSHeader::setName(CSString *name)
73
void CSHeader::setValue(const char *value)
75
iValue = CSString::newString(value);
78
void CSHeader::setValue(const char *value, uint32_t len)
80
iValue = CSString::newString(value, len);
83
void CSHeader::setValue(CSString *value)
88
void CSHeader::write(CSOutputStream *out)
96
void CSHTTPHeaders::clearHeaders()
99
iExpect100Continue = false;
100
iUnknownEpectHeader = false;
106
CSVector *CSHTTPHeaders::takeHeaders()
108
CSVector *headers = iHeaders;
113
void CSHTTPHeaders::setHeaders(CSVector *headers)
120
void CSHTTPHeaders::addHeader(CSHeader *h)
123
new_(iHeaders, CSVector(5));
125
if (strcasecmp(h->getNameCString(), "Connection") == 0 && strcasecmp(h->getValueCString(), "Keep-Alive") == 0)
128
if (strcasecmp(h->getNameCString(), "Expect") == 0) {
129
if (strcasecmp(h->getValueCString(), "100-continue") == 0)
130
iExpect100Continue = true;
132
iUnknownEpectHeader = true;
138
void CSHTTPHeaders::addHeaders(CSHTTPHeaders *headers)
142
while ((h = headers->getHeader(i++))) {
147
void CSHTTPHeaders::addHeader(const char *name, const char *value)
153
new_(iHeaders, CSVector(5));
165
void CSHTTPHeaders::addHeader(const char *name, uint32_t nlen, const char *value, uint32_t vlen)
171
new_(iHeaders, CSVector(5));
175
h->setName(name, nlen);
176
h->setValue(value, vlen);
182
void CSHTTPHeaders::addHeader(CSString *name, CSString *value)
190
new_(iHeaders, CSVector(5));
201
void CSHTTPHeaders::addHeader(const char *name, CSString *value)
208
n = CSString::newString(name);
211
new_(iHeaders, CSVector(5));
221
void CSHTTPHeaders::removeHeader(CSString *name)
228
for (uint32_t i=0; i<iHeaders->size(); ) {
229
h = (CSHeader *) iHeaders->get(i);
230
if (h->getName()->compare(name) == 0) {
241
void CSHTTPHeaders::removeHeader(const char *name)
243
removeHeader(CSString::newString(name));
246
CSString *CSHTTPHeaders::getHeaderValue(const char *name)
252
n = CSString::newString(name);
258
for (uint32_t i=0; i<iHeaders->size(); i++) {
259
h = (CSHeader *) iHeaders->get(i);
260
if (h->getName()->compare(n) == 0) {
271
void CSHTTPHeaders::writeHeader(CSOutputStream *out)
276
for (uint32_t i=0; i<iHeaders->size(); i++) {
277
h = (CSHeader *) iHeaders->get(i);
283
bool CSHTTPHeaders::keepAlive()
288
bool CSHTTPHeaders::expect100Continue()
290
return iExpect100Continue;
293
bool CSHTTPHeaders::unknownEpectHeader()
295
return iUnknownEpectHeader;
299
* ---------------------------------------------------------------
303
CSHTTPInputStream::CSHTTPInputStream(CSInputStream* in):
314
CSHTTPInputStream::~CSHTTPInputStream()
321
void CSHTTPInputStream::readHead()
323
CSStringBuffer *sb = NULL;
324
bool first_line = true;
330
sb = iInput->readLine();
334
printf("HTTP: %s\n", sb->getCString());
336
if (sb->length() == 0) {
344
start = sb->ignore(0, ' ');
345
end = sb->find(start, ' ');
346
str = sb->substr(start, end - start);
347
if (str->startsWith("HTTP")) { // Reply header
351
start = sb->ignore(end, ' ');
352
end = sb->find(start, ' ');
354
CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
356
str = sb->substr(start, end - start);
357
iStatus = atol(str->getCString());
359
start = sb->ignore(end, ' ');
360
end = sb->find(start, '\r');
362
CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
363
iStatusPhrase = sb->substr(start, end - start);
366
iStatusPhrase = NULL;
368
start = sb->ignore(end, ' ');
369
end = sb->find(start, ' ');
371
CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
372
iRequestURI = sb->substr(start, end - start);
373
start = sb->ignore(end, ' ');
374
end = sb->find(start, ' ');
376
CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
377
iHTTPVersion = sb->substr(start, end - start);
382
uint32_t nstart, nend;
383
uint32_t vstart, vend;
385
nstart = sb->ignore(0, ' ');
386
nend = sb->find(nstart, ':');
388
vstart = sb->ignore(nend+1, ' ');
389
vend = sb->find(vstart, '\r');
391
nend = sb->trim(nend, ' ');
392
vend = sb->trim(vend, ' ');
395
CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
396
addHeader(sb->getBuffer(nstart), nend-nstart, sb->getBuffer(vstart), vend-vstart);
404
bool CSHTTPInputStream::getRange(uint64_t *size, uint64_t *offset)
407
bool haveRange = false;
409
if ((val = getHeaderValue("Range"))) {
410
uint64_t first_byte = 0, last_byte = 0;
411
const char *range = val->getCString();
413
if (range && (val->compare("bytes=", 6) == 0)) {
414
if ((sscanf(range + 6, "%"PRIu64"-%"PRIu64"", &first_byte, &last_byte) == 2) && (last_byte >= first_byte)) {
415
*offset = (uint64_t) first_byte;
416
*size =last_byte - first_byte + 1;
426
uint64_t CSHTTPInputStream::getContentLength()
431
if ((val = getHeaderValue("Content-Length"))) {
432
const char *len = val->getCString();
435
sscanf(len, "%"PRIu64"", &size);
441
const char *CSHTTPInputStream::getMethod()
445
return iMethod->getCString();
448
void CSHTTPInputStream::close()
455
size_t CSHTTPInputStream::read(char *b, size_t len)
458
return_(iInput->read(b, len));
461
int CSHTTPInputStream::read()
464
return_(iInput->read());
467
int CSHTTPInputStream::peek()
470
return_(iInput->peek());
473
void CSHTTPInputStream::freeHead()
482
iRequestURI->release();
486
iHTTPVersion->release();
490
iStatusPhrase->release();
491
iStatusPhrase = NULL;
497
CSHTTPInputStream *CSHTTPInputStream::newStream(CSInputStream* i)
499
CSHTTPInputStream *s;
501
if (!(s = new CSHTTPInputStream(i))) {
503
CSException::throwOSError(CS_CONTEXT, ENOMEM);
509
* ---------------------------------------------------------------
510
* HTTP OUTPUT STREAMS
513
CSHTTPOutputStream::CSHTTPOutputStream(CSOutputStream* out):
523
iBody.setGrowSize(120);
526
CSHTTPOutputStream::~CSHTTPOutputStream()
534
void CSHTTPOutputStream::writeHeaders()
540
void CSHTTPOutputStream::writeHead()
542
iOutput->print("HTTP/1.1 ");
543
iOutput->print(iStatus);
545
iOutput->print(getReasonPhrase(iStatus));
546
iOutput->print("\r\n");
547
writeHeader(iOutput);
548
iOutput->print("Content-Length: ");
549
iOutput->print(iContentLength);
550
iOutput->print("\r\n");
551
if (iRangeSize && (iStatus == 200)) {
552
iOutput->print("Content-Range: bytes ");
553
iOutput->print(iRangeOffset);
555
iOutput->print(iRangeOffset + iRangeSize -1);
557
iOutput->print(iTotalLength);
558
iOutput->print("\r\n");
560
iOutput->print("\r\n");
563
void CSHTTPOutputStream::clearBody()
572
void CSHTTPOutputStream::writeBody()
574
iOutput->write(iBody.getBuffer(0), iBody.length());
577
void CSHTTPOutputStream::appendBody(const char *str)
580
iContentLength = iBody.length();
583
void CSHTTPOutputStream::appendBody(int value)
586
iContentLength = iBody.length();
589
void CSHTTPOutputStream::close()
596
void CSHTTPOutputStream::write(const char *b, size_t len)
599
iOutput->write(b, len);
603
void CSHTTPOutputStream::flush()
610
void CSHTTPOutputStream::write(char b)
617
const char *CSHTTPOutputStream::getReasonPhrase(int code)
619
const char *message = "Unknown Code";
622
case 100: message = "Continue"; break;
623
case 101: message = "Switching Protocols"; break;
624
case 200: message = "OK"; break;
625
case 201: message = "Created"; break;
626
case 202: message = "Accepted"; break;
627
case 203: message = "Non-Authoritative Information"; break;
628
case 204: message = "No Content"; break;
629
case 205: message = "Reset Content"; break;
630
case 206: message = "Partial Content"; break;
631
case 300: message = "Multiple Choices"; break;
632
case 301: message = "Moved Permanently"; break;
633
case 302: message = "Found"; break;
634
case 303: message = "See Other"; break;
635
case 304: message = "Not Modified"; break;
636
case 305: message = "Use Proxy"; break;
637
case 307: message = "Temporary Redirect"; break;
638
case 400: message = "Bad Request"; break;
639
case 401: message = "Unauthorized"; break;
640
case 402: message = "Payment Required"; break;
641
case 403: message = "Forbidden"; break;
642
case 404: message = "Not Found"; break;
643
case 405: message = "Method Not Allowed"; break;
644
case 406: message = "Not Acceptable"; break;
645
case 407: message = "Proxy Authentication Required"; break;
646
case 408: message = "Request Time-out"; break;
647
case 409: message = "Conflict"; break;
648
case 410: message = "Gone"; break;
649
case 411: message = "Length Required"; break;
650
case 412: message = "Precondition Failed"; break;
651
case 413: message = "Request Entity Too Large"; break;
652
case 414: message = "Request-URI Too Large"; break;
653
case 415: message = "Unsupported Media Type"; break;
654
case 416: message = "Requested range not satisfiable"; break;
655
case 417: message = "Expectation Failed"; break;
656
case 500: message = "Internal Server Error"; break;
657
case 501: message = "Not Implemented"; break;
658
case 502: message = "Bad Gateway"; break;
659
case 503: message = "Service Unavailable"; break;
660
case 504: message = "Gateway Time-out"; break;
661
case 505: message = "HTTP Version not supported"; break;
666
CSHTTPOutputStream *CSHTTPOutputStream::newStream(CSOutputStream* i)
668
CSHTTPOutputStream *s;
670
if (!(s = new CSHTTPOutputStream(i))) {
672
CSException::throwOSError(CS_CONTEXT, ENOMEM);