~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbms/src/cslib/CSHTTPStream.cc

  • Committer: Monty Taylor
  • Date: 2008-08-05 19:01:20 UTC
  • mto: (266.1.1 codestyle)
  • mto: This revision was merged to the branch mainline in revision 266.
  • Revision ID: monty@inaugust.com-20080805190120-tsuziqz2mfqcw7pe
Removed libmysyslt.la, made mysys a noinst_ and made everything use it. It's
not a standalone lib, there's no reason to pretend otherwise.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
2
 
 *
3
 
 * PrimeBase Media Stream for MySQL
4
 
 *
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.
9
 
 *
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.
14
 
 *
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
18
 
 *
19
 
 * Original author: Paul McCullagh (H&G2JCtL)
20
 
 * Continued development: Barry Leslie
21
 
 *
22
 
 * 2007-06-10
23
 
 *
24
 
 * A basic syncronized object.
25
 
 *
26
 
 */
27
 
#include "CSConfig.h"
28
 
 
29
 
#include <stdlib.h>
30
 
#include <inttypes.h>
31
 
 
32
 
#include "string.h"
33
 
 
34
 
#include "CSHTTPStream.h"
35
 
#include "CSGlobal.h"
36
 
 
37
 
#ifdef DEBUG
38
 
//#define PRINT_HEADER
39
 
#endif
40
 
 
41
 
/*
42
 
 * ---------------------------------------------------------------
43
 
 * HTTP HEADERS
44
 
 */
45
 
 
46
 
CSHeader::~CSHeader()
47
 
{
48
 
        if (iName) {
49
 
                iName->release();
50
 
                iName = NULL;
51
 
        }
52
 
        if (iValue) {
53
 
                iValue->release();
54
 
                iValue = NULL;
55
 
        }
56
 
}
57
 
 
58
 
void CSHeader::setName(const char *name)
59
 
{
60
 
        iName = CSString::newString(name);
61
 
}
62
 
 
63
 
void CSHeader::setName(const char *name, uint32_t len)
64
 
{
65
 
        iName = CSString::newString(name, len);
66
 
}
67
 
 
68
 
void CSHeader::setName(CSString *name)
69
 
{
70
 
        iName = name;
71
 
}
72
 
 
73
 
void CSHeader::setValue(const char *value)
74
 
{
75
 
        iValue = CSString::newString(value);
76
 
}
77
 
 
78
 
void CSHeader::setValue(const char *value, uint32_t len)
79
 
{
80
 
        iValue = CSString::newString(value, len);
81
 
}
82
 
 
83
 
void CSHeader::setValue(CSString *value)
84
 
{
85
 
        iValue = value;
86
 
}
87
 
 
88
 
void CSHeader::write(CSOutputStream *out)
89
 
{
90
 
        out->print(iName);
91
 
        out->print(": ");
92
 
        out->print(iValue);
93
 
        out->print("\r\n");
94
 
}
95
 
 
96
 
void CSHTTPHeaders::clearHeaders()
97
 
{
98
 
        iKeepAlive = false;
99
 
        iExpect100Continue = false;
100
 
        iUnknownEpectHeader = false;
101
 
        if (iHeaders) {
102
 
                iHeaders->release();
103
 
                iHeaders = NULL;
104
 
        }
105
 
}
106
 
CSVector *CSHTTPHeaders::takeHeaders()
107
 
{
108
 
        CSVector *headers = iHeaders;
109
 
        iHeaders = NULL;
110
 
        return headers;
111
 
}
112
 
 
113
 
void CSHTTPHeaders::setHeaders(CSVector *headers)
114
 
{
115
 
        if (iHeaders) 
116
 
                iHeaders->release();
117
 
        iHeaders = headers;
118
 
}
119
 
 
120
 
void CSHTTPHeaders::addHeader(CSHeader *h)
121
 
{
122
 
        if (!iHeaders)
123
 
                new_(iHeaders, CSVector(5));
124
 
 
125
 
        if (strcasecmp(h->getNameCString(), "Connection") == 0 && strcasecmp(h->getValueCString(), "Keep-Alive") == 0)
126
 
                iKeepAlive = true;
127
 
                
128
 
        if (strcasecmp(h->getNameCString(), "Expect") == 0) {
129
 
                if (strcasecmp(h->getValueCString(), "100-continue") == 0)
130
 
                        iExpect100Continue = true;
131
 
                else
132
 
                        iUnknownEpectHeader = true;
133
 
        }
134
 
                
135
 
        iHeaders->add(h);
136
 
}
137
 
 
138
 
void CSHTTPHeaders::addHeaders(CSHTTPHeaders *headers)
139
 
{
140
 
        CSHeader *h;
141
 
        uint32_t i =0;
142
 
        while ((h = headers->getHeader(i++))) {
143
 
                addHeader(h);
144
 
        }
145
 
}
146
 
 
147
 
void CSHTTPHeaders::addHeader(const char *name, const char *value)
148
 
{
149
 
        CSHeader *h;
150
 
 
151
 
        enter_();
152
 
        if (!iHeaders)
153
 
                new_(iHeaders, CSVector(5));
154
 
 
155
 
        new_(h, CSHeader());
156
 
        push_(h);
157
 
        h->setName(name);
158
 
        h->setValue(value);
159
 
        pop_(h);
160
 
 
161
 
        addHeader(h);
162
 
        exit_();
163
 
}
164
 
 
165
 
void CSHTTPHeaders::addHeader(const char *name, uint32_t nlen, const char *value, uint32_t vlen)
166
 
{
167
 
        CSHeader *h;
168
 
 
169
 
        enter_();
170
 
        if (!iHeaders)
171
 
                new_(iHeaders, CSVector(5));
172
 
 
173
 
        new_(h, CSHeader());
174
 
        push_(h);
175
 
        h->setName(name, nlen);
176
 
        h->setValue(value, vlen);
177
 
        pop_(h);
178
 
        addHeader(h);
179
 
        exit_();
180
 
}
181
 
 
182
 
void CSHTTPHeaders::addHeader(CSString *name, CSString *value)
183
 
{
184
 
        CSHeader *h;
185
 
 
186
 
        enter_();
187
 
        push_(name);
188
 
        push_(value);
189
 
        if (!iHeaders)
190
 
                new_(iHeaders, CSVector(5));
191
 
 
192
 
        new_(h, CSHeader());
193
 
        pop_(value);
194
 
        pop_(name);
195
 
        h->setName(name);
196
 
        h->setValue(value);
197
 
        addHeader(h);
198
 
        exit_();
199
 
}
200
 
 
201
 
void CSHTTPHeaders::addHeader(const char *name, CSString *value)
202
 
{
203
 
        CSHeader *h;
204
 
        CSString *n;
205
 
 
206
 
        enter_();
207
 
        push_(value);
208
 
        n = CSString::newString(name);
209
 
        push_(n);
210
 
        if (!iHeaders)
211
 
                new_(iHeaders, CSVector(5));
212
 
        new_(h, CSHeader());
213
 
        pop_(n);
214
 
        pop_(value);
215
 
        h->setName(n);
216
 
        h->setValue(value);
217
 
        addHeader(h);
218
 
        exit_();
219
 
}
220
 
 
221
 
void CSHTTPHeaders::removeHeader(CSString *name)
222
 
{
223
 
        enter_();
224
 
        push_(name);
225
 
        if (iHeaders) {
226
 
                CSHeader *h;
227
 
 
228
 
                for (uint32_t i=0; i<iHeaders->size(); ) {
229
 
                        h = (CSHeader *) iHeaders->get(i);
230
 
                        if (h->getName()->compare(name) == 0) {
231
 
                                iHeaders->remove(i);
232
 
                        } else 
233
 
                                i++;
234
 
                }
235
 
        }
236
 
        release_(name);
237
 
        
238
 
        exit_();
239
 
}
240
 
 
241
 
void CSHTTPHeaders::removeHeader(const char *name)
242
 
{
243
 
        removeHeader(CSString::newString(name));
244
 
}
245
 
 
246
 
CSString *CSHTTPHeaders::getHeaderValue(const char *name)
247
 
{
248
 
        CSString *n;
249
 
        CSString *v;
250
 
 
251
 
        enter_();
252
 
        n = CSString::newString(name);
253
 
        push_(n);
254
 
        v = NULL;
255
 
        if (iHeaders) {
256
 
                CSHeader *h;
257
 
 
258
 
                for (uint32_t i=0; i<iHeaders->size(); i++) {
259
 
                        h = (CSHeader *) iHeaders->get(i);
260
 
                        if (h->getName()->compare(n) == 0) {
261
 
                                v = h->getValue();
262
 
                                v->retain();
263
 
                                break;
264
 
                        }
265
 
                }
266
 
        }
267
 
        release_(n);
268
 
        return_(v);
269
 
}
270
 
 
271
 
void CSHTTPHeaders::writeHeader(CSOutputStream *out)
272
 
{
273
 
        if (iHeaders) {
274
 
                CSHeader *h;
275
 
 
276
 
                for (uint32_t i=0; i<iHeaders->size(); i++) {
277
 
                        h = (CSHeader *) iHeaders->get(i);
278
 
                        h->write(out);
279
 
                }
280
 
        }
281
 
}
282
 
 
283
 
bool CSHTTPHeaders::keepAlive()
284
 
{
285
 
        return iKeepAlive;
286
 
}
287
 
 
288
 
bool CSHTTPHeaders::expect100Continue()
289
 
{
290
 
        return iExpect100Continue;
291
 
}
292
 
 
293
 
bool CSHTTPHeaders::unknownEpectHeader()
294
 
{
295
 
        return iUnknownEpectHeader;
296
 
}
297
 
 
298
 
/*
299
 
 * ---------------------------------------------------------------
300
 
 * HTTP INPUT STREAMS
301
 
 */
302
 
 
303
 
CSHTTPInputStream::CSHTTPInputStream(CSInputStream* in):
304
 
CSHTTPHeaders(),
305
 
iInput(NULL),
306
 
iMethod(NULL),
307
 
iRequestURI(NULL),
308
 
iHTTPVersion(NULL),
309
 
iStatusPhrase(NULL)
310
 
{
311
 
        iInput = in;
312
 
}
313
 
 
314
 
CSHTTPInputStream::~CSHTTPInputStream()
315
 
{
316
 
        freeHead();
317
 
        if (iInput)
318
 
                iInput->release();
319
 
}
320
 
 
321
 
void CSHTTPInputStream::readHead()
322
 
{
323
 
        CSStringBuffer  *sb = NULL;
324
 
        bool                    first_line = true;
325
 
        uint32_t                        start, end;
326
 
 
327
 
        enter_();
328
 
        freeHead();
329
 
        for (;;) {
330
 
                sb = iInput->readLine();
331
 
                if (!sb)
332
 
                        break;
333
 
#ifdef PRINT_HEADER
334
 
                printf("HTTP: %s\n", sb->getCString());
335
 
#endif
336
 
                if (sb->length() == 0) {
337
 
                        sb->release();
338
 
                        break;
339
 
                }
340
 
                push_(sb);
341
 
                
342
 
                if (first_line) {
343
 
                        CSString *str;
344
 
                        start = sb->ignore(0, ' ');
345
 
                        end = sb->find(start, ' ');
346
 
                        str = sb->substr(start, end - start);
347
 
                        if (str->startsWith("HTTP")) { // Reply header
348
 
                                iMethod = NULL;
349
 
                                iRequestURI = NULL;
350
 
                                iHTTPVersion = str;
351
 
                                start = sb->ignore(end, ' ');
352
 
                                end = sb->find(start, ' ');
353
 
                                if (start > end)
354
 
                                        CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
355
 
 
356
 
                                str = sb->substr(start, end - start);
357
 
                                iStatus = atol(str->getCString());
358
 
                                str->release();
359
 
                                start = sb->ignore(end, ' ');
360
 
                                end = sb->find(start, '\r');
361
 
                                if (start > end)
362
 
                                        CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
363
 
                                iStatusPhrase = sb->substr(start, end - start);
364
 
                        } else {
365
 
                                iStatus = 0;
366
 
                                iStatusPhrase = NULL;
367
 
                                iMethod = str;
368
 
                        start = sb->ignore(end, ' ');
369
 
                        end = sb->find(start, ' ');
370
 
                        if (start > end)
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, ' ');
375
 
                        if (start > end)
376
 
                                CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HTTP_HEADER, "Bad HTTP header");
377
 
                        iHTTPVersion = sb->substr(start, end - start);
378
 
                        }                               
379
 
                        first_line = false;
380
 
                }
381
 
                else {
382
 
                        uint32_t nstart, nend;
383
 
                        uint32_t vstart, vend;
384
 
 
385
 
                        nstart = sb->ignore(0, ' ');
386
 
                        nend = sb->find(nstart, ':');
387
 
 
388
 
                        vstart = sb->ignore(nend+1, ' ');
389
 
                        vend = sb->find(vstart, '\r');
390
 
 
391
 
                        nend = sb->trim(nend, ' ');
392
 
                        vend = sb->trim(vend, ' ');
393
 
                        
394
 
                        if (vstart > 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);
397
 
                }
398
 
 
399
 
                release_(sb);
400
 
        }
401
 
        exit_();
402
 
}
403
 
 
404
 
bool CSHTTPInputStream::getRange(uint64_t *size, uint64_t *offset)
405
 
{
406
 
        CSString        *val;
407
 
        bool haveRange = false;
408
 
 
409
 
        if ((val = getHeaderValue("Range"))) {
410
 
                uint64_t                first_byte = 0, last_byte = 0;
411
 
                const char      *range = val->getCString();
412
 
                
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;
417
 
                                haveRange = true;
418
 
                        }       
419
 
                }
420
 
                val->release();
421
 
                                
422
 
        }
423
 
        return haveRange;
424
 
}
425
 
 
426
 
uint64_t CSHTTPInputStream::getContentLength()
427
 
{
428
 
        CSString        *val;
429
 
        uint64_t                size = 0;
430
 
 
431
 
        if ((val = getHeaderValue("Content-Length"))) {
432
 
                const char      *len = val->getCString();
433
 
 
434
 
                if (len)  
435
 
                        sscanf(len, "%"PRIu64"", &size);                
436
 
                val->release();
437
 
        }
438
 
        return size;
439
 
}
440
 
 
441
 
const char *CSHTTPInputStream::getMethod()
442
 
{
443
 
        if (!iMethod)
444
 
                return NULL;
445
 
        return iMethod->getCString();
446
 
}
447
 
 
448
 
void CSHTTPInputStream::close()
449
 
{
450
 
        enter_();
451
 
        iInput->close();
452
 
        exit_();
453
 
}
454
 
 
455
 
size_t CSHTTPInputStream::read(char *b, size_t len)
456
 
{
457
 
        enter_();
458
 
        return_(iInput->read(b, len));
459
 
}
460
 
 
461
 
int CSHTTPInputStream::read()
462
 
{
463
 
        enter_();
464
 
        return_(iInput->read());
465
 
}
466
 
 
467
 
int CSHTTPInputStream::peek()
468
 
{
469
 
        enter_();
470
 
        return_(iInput->peek());
471
 
}
472
 
 
473
 
void CSHTTPInputStream::freeHead()
474
 
{
475
 
        enter_();
476
 
        clearHeaders();
477
 
        if (iMethod) {
478
 
                iMethod->release();
479
 
                iMethod = NULL;
480
 
        }
481
 
        if (iRequestURI) {
482
 
                iRequestURI->release();
483
 
                iRequestURI = NULL;
484
 
        }
485
 
        if (iHTTPVersion) {
486
 
                iHTTPVersion->release();
487
 
                iHTTPVersion = NULL;
488
 
        }
489
 
        if (iStatusPhrase) {
490
 
                iStatusPhrase->release();
491
 
                iStatusPhrase = NULL;
492
 
        }
493
 
        iStatus = 0;
494
 
        exit_();
495
 
}
496
 
 
497
 
CSHTTPInputStream *CSHTTPInputStream::newStream(CSInputStream* i)
498
 
{
499
 
        CSHTTPInputStream *s;
500
 
 
501
 
        if (!(s = new CSHTTPInputStream(i))) {
502
 
                i->release();
503
 
                CSException::throwOSError(CS_CONTEXT, ENOMEM);
504
 
        }
505
 
        return s;
506
 
}
507
 
 
508
 
/*
509
 
 * ---------------------------------------------------------------
510
 
 * HTTP OUTPUT STREAMS
511
 
 */
512
 
 
513
 
CSHTTPOutputStream::CSHTTPOutputStream(CSOutputStream* out):
514
 
CSHTTPHeaders(),
515
 
iOutput(NULL),
516
 
iStatus(0),
517
 
iContentLength(0),
518
 
iRangeSize(0),
519
 
iRangeOffset(0),
520
 
iTotalLength(0)
521
 
{
522
 
        iOutput = out;
523
 
        iBody.setGrowSize(120);
524
 
}
525
 
 
526
 
CSHTTPOutputStream::~CSHTTPOutputStream()
527
 
{
528
 
        clearHeaders();
529
 
        clearBody();
530
 
        if (iOutput)
531
 
                iOutput->release();
532
 
}
533
 
 
534
 
void CSHTTPOutputStream::writeHeaders()
535
 
{
536
 
        writeHeader(this);
537
 
        clearHeaders();
538
 
}
539
 
 
540
 
void CSHTTPOutputStream::writeHead()
541
 
{
542
 
        iOutput->print("HTTP/1.1 ");
543
 
        iOutput->print(iStatus);
544
 
        iOutput->print(" ");
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);
554
 
                iOutput->print("-");
555
 
                iOutput->print(iRangeOffset + iRangeSize -1);
556
 
                iOutput->print("/");
557
 
                iOutput->print(iTotalLength);
558
 
                iOutput->print("\r\n");
559
 
        }
560
 
        iOutput->print("\r\n");
561
 
}
562
 
 
563
 
void CSHTTPOutputStream::clearBody()
564
 
{
565
 
        iRangeSize = 0;
566
 
        iRangeOffset = 0;
567
 
        iTotalLength = 0;
568
 
        iContentLength = 0;
569
 
        iBody.clear();
570
 
}
571
 
 
572
 
void CSHTTPOutputStream::writeBody()
573
 
{
574
 
        iOutput->write(iBody.getBuffer(0), iBody.length());
575
 
}
576
 
 
577
 
void CSHTTPOutputStream::appendBody(const char *str)
578
 
{
579
 
        iBody.append(str);
580
 
        iContentLength = iBody.length();
581
 
}
582
 
 
583
 
void CSHTTPOutputStream::appendBody(int value)
584
 
{
585
 
        iBody.append(value);
586
 
        iContentLength = iBody.length();
587
 
}
588
 
 
589
 
void CSHTTPOutputStream::close()
590
 
{
591
 
        enter_();
592
 
        iOutput->close();
593
 
        exit_();
594
 
}
595
 
 
596
 
void CSHTTPOutputStream::write(const char *b, size_t len)
597
 
{
598
 
        enter_();
599
 
        iOutput->write(b, len);
600
 
        exit_();
601
 
}
602
 
 
603
 
void CSHTTPOutputStream::flush()
604
 
{
605
 
        enter_();
606
 
        iOutput->flush();
607
 
        exit_();
608
 
}
609
 
 
610
 
void CSHTTPOutputStream::write(char b)
611
 
{
612
 
        enter_();
613
 
        iOutput->write(b);
614
 
        exit_();
615
 
}
616
 
 
617
 
const char *CSHTTPOutputStream::getReasonPhrase(int code)
618
 
{
619
 
        const char *message = "Unknown Code";
620
 
 
621
 
        switch (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;
662
 
        }
663
 
        return message;
664
 
}
665
 
 
666
 
CSHTTPOutputStream *CSHTTPOutputStream::newStream(CSOutputStream* i)
667
 
{
668
 
        CSHTTPOutputStream *s;
669
 
 
670
 
        if (!(s = new CSHTTPOutputStream(i))) {
671
 
                i->release();
672
 
                CSException::throwOSError(CS_CONTEXT, ENOMEM);
673
 
        }
674
 
        return s;
675
 
}
676
 
 
677