~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbms/src/connection_handler_ms.cc

  • Committer: Mark Atwood
  • Date: 2011-12-20 02:32:53 UTC
  • mfrom: (2469.1.1 drizzle-build)
  • Revision ID: me@mark.atwood.name-20111220023253-bvu0kr14kwsdvz7g
mergeĀ lp:~brianaker/drizzle/deprecate-pbms

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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
 
 *
19
 
 * Original author: Paul McCullagh
20
 
 * Continued development: Barry Leslie
21
 
 *
22
 
 * 2007-05-25
23
 
 *
24
 
 * H&G2JCtL
25
 
 *
26
 
 * Network interface.
27
 
 *
28
 
 */
29
 
 
30
 
#include "cslib/CSConfig.h"
31
 
#include <inttypes.h>
32
 
 
33
 
#include "defs_ms.h"
34
 
 
35
 
#include "cslib/CSGlobal.h"
36
 
#include "cslib/CSSocket.h"
37
 
#include "cslib/CSStrUtil.h"
38
 
#include "cslib/CSHTTPStream.h"
39
 
 
40
 
#include "connection_handler_ms.h"
41
 
#include "network_ms.h"
42
 
#include "open_table_ms.h"
43
 
#include "engine_ms.h"
44
 
#include "version_ms.h"
45
 
 
46
 
//#include "mysql_ms.h"
47
 
 
48
 
u_long MSConnectionHandler::gMaxKeepAlive;
49
 
 
50
 
MSConnectionHandler::MSConnectionHandler(CSThreadList *list):
51
 
        CSDaemon(list),
52
 
        amWaitingToListen(false),
53
 
        shuttingDown(false),
54
 
        lastUse(0),
55
 
        replyPending(false),
56
 
        iInputStream(NULL),
57
 
        iOutputStream(NULL),
58
 
        iTableURI(NULL)
59
 
{
60
 
}
61
 
 
62
 
void MSConnectionHandler::close()
63
 
{
64
 
        closeStream();
65
 
        freeRequestURI();
66
 
}
67
 
 
68
 
MSConnectionHandler *MSConnectionHandler::newHandler(CSThreadList *list)
69
 
{
70
 
        return new MSConnectionHandler(list);
71
 
}
72
 
 
73
 
/* Return false if not connection was openned, and the thread must quit. */
74
 
bool MSConnectionHandler::openStream()
75
 
{
76
 
        CSSocket                *sock;
77
 
        CSInputStream   *in;
78
 
        CSOutputStream  *out;
79
 
        
80
 
        enter_();
81
 
        if (!(sock = MSNetwork::openConnection(this)))
82
 
                return_(false);
83
 
        push_(sock);
84
 
        in = sock->getInputStream();
85
 
        in = CSBufferedInputStream::newStream(in);
86
 
        iInputStream = CSHTTPInputStream::newStream(in);
87
 
 
88
 
        out = sock->getOutputStream();
89
 
        out = CSBufferedOutputStream::newStream(out);
90
 
        iOutputStream = CSHTTPOutputStream::newStream(out);
91
 
        release_(sock);
92
 
        return_(true);
93
 
}
94
 
 
95
 
int MSConnectionHandler::getHTTPStatus(int err)
96
 
{
97
 
        int code;
98
 
 
99
 
        switch (err) {
100
 
                case MS_OK:                                             code = 200; break;
101
 
                case MS_ERR_ENGINE:                             code = 500; break;
102
 
                case MS_ERR_UNKNOWN_TABLE:              code = 404; break;
103
 
                case MS_ERR_UNKNOWN_DB:                 code = 404; break;
104
 
                case MS_ERR_DATABASE_DELETED:   code = 404; break;
105
 
                case MS_ERR_NOT_FOUND:                  code = 404; break;
106
 
                case MS_ERR_REMOVING_REPO:              code = 404; break;
107
 
                case MS_ERR_TABLE_LOCKED:               code = 412; break; // Precondition Failed
108
 
                case MS_ERR_INCORRECT_URL:              code = 404; break;
109
 
                case MS_ERR_AUTH_FAILED:                code = 403; break; // Forbidden
110
 
                default:                                                code = 500; break;
111
 
        }
112
 
        return code;
113
 
}
114
 
 
115
 
void MSConnectionHandler::writeException(const char *qualifier)
116
 
{
117
 
        int code;
118
 
 
119
 
        enter_();
120
 
        iOutputStream->clearHeaders();
121
 
        iOutputStream->clearBody();
122
 
        code = getHTTPStatus(myException.getErrorCode());
123
 
        iOutputStream->setStatus(code);
124
 
        iOutputStream->appendBody("<HTML><HEAD><TITLE>HTTP Error ");
125
 
        iOutputStream->appendBody(code);
126
 
        iOutputStream->appendBody(": ");
127
 
        iOutputStream->appendBody(CSHTTPOutputStream::getReasonPhrase(code));
128
 
        iOutputStream->appendBody("</TITLE></HEAD>");
129
 
        iOutputStream->appendBody("<BODY><H2>HTTP Error ");
130
 
        iOutputStream->appendBody(code);
131
 
        iOutputStream->appendBody(": ");
132
 
        iOutputStream->appendBody(CSHTTPOutputStream::getReasonPhrase(code));
133
 
        iOutputStream->appendBody("</H2>");
134
 
        if (qualifier)
135
 
                iOutputStream->appendBody(qualifier);
136
 
        iOutputStream->appendBody(EXCEPTION_REPLY_MESSAGE_PREFIX_TAG);
137
 
        iOutputStream->appendBody(myException.getMessage());
138
 
        iOutputStream->appendBody(EXCEPTION_REPLY_MESSAGE_SUFFIX_TAG);
139
 
        iOutputStream->appendBody(myException.getStackTrace());
140
 
        iOutputStream->appendBody(EXCEPTION_REPLY_STACK_TRACE_SUFFIX_TAG);
141
 
        iOutputStream->appendBody("MySQL ");
142
 
        iOutputStream->appendBody(PBMSVersion::getCString());
143
 
        iOutputStream->appendBody(", PBMS ");
144
 
        iOutputStream->appendBody(PBMSVersion::getCString());
145
 
        iOutputStream->appendBody("<br>Copyright &#169; 2009, PrimeBase Technologies GmbH</font></P></BODY></HTML>");
146
 
 
147
 
        replyPending = false;
148
 
        iOutputStream->writeHead();
149
 
        iOutputStream->writeBody();
150
 
        iOutputStream->flush();
151
 
        exit_();
152
 
}
153
 
 
154
 
void MSConnectionHandler::writeException()
155
 
{
156
 
        writeException(NULL);
157
 
}
158
 
 
159
 
void MSConnectionHandler::closeStream()
160
 
{
161
 
        enter_();
162
 
        if (iOutputStream) {
163
 
                if (replyPending) {
164
 
                        try_(a) {
165
 
                                writeException();
166
 
                        }
167
 
                        catch_(a) {
168
 
                        }
169
 
                        cont_(a);
170
 
                }
171
 
                iOutputStream->release();
172
 
                iOutputStream = NULL;
173
 
        }
174
 
        if (iInputStream) {
175
 
                iInputStream->release();
176
 
                iInputStream = NULL;
177
 
        }
178
 
        exit_();
179
 
}
180
 
 
181
 
void MSConnectionHandler::parseRequestURI()
182
 
{
183
 
        CSString        *uri = iInputStream->getRequestURI();
184
 
        uint32_t                pos = 0, end;
185
 
        enter_();
186
 
        (void)end;
187
 
        
188
 
        freeRequestURI();
189
 
        pos = uri->locate(0, "://");
190
 
        if (pos < uri->length())
191
 
                pos += 3;
192
 
        else
193
 
                pos = uri->skip(0, '/');
194
 
 
195
 
        // Table URI
196
 
        end = uri->locate(pos, '/');
197
 
        //end = uri->locate(uri->nextPos(end), '/'); I am not sure why this was done.
198
 
        //iTableURI = uri->substr(pos, end - pos);
199
 
        iTableURI = uri->substr(pos);
200
 
 
201
 
        exit_();
202
 
}
203
 
 
204
 
void MSConnectionHandler::freeRequestURI()
205
 
{
206
 
        if (iTableURI)
207
 
                iTableURI->release();
208
 
        iTableURI = NULL;
209
 
}
210
 
 
211
 
void MSConnectionHandler::writeFile(CSString *file_path)
212
 
{
213
 
        CSPath                  *path;
214
 
        CSFile                  *file;
215
 
 
216
 
        enter_();
217
 
        push_(file_path);
218
 
 
219
 
        path = CSPath::newPath(RETAIN(file_path));
220
 
        pop_(file_path);
221
 
        push_(path);
222
 
        if (path->exists()) {
223
 
                file = path->openFile(CSFile::READONLY);
224
 
                push_(file);
225
 
 
226
 
                iOutputStream->setContentLength((uint64_t) path->getSize());
227
 
                replyPending = false;
228
 
                iOutputStream->writeHead();
229
 
                
230
 
                CSStream::pipe(RETAIN(iOutputStream), file->getInputStream());
231
 
 
232
 
                release_(file);
233
 
        }
234
 
        else {
235
 
                myException.initFileError(CS_CONTEXT, path->getCString(), ENOENT);
236
 
                writeException();
237
 
        }
238
 
        release_(path);
239
 
 
240
 
        exit_();
241
 
}
242
 
 
243
 
/*
244
 
 * Request URI: /<blob URL>
245
 
* OR
246
 
 * Request URI: /<database>/<blob alias>
247
 
 */
248
 
void MSConnectionHandler::handleGet(bool info_only)
249
 
{
250
 
        const char      *bad_url_comment = "Incorrect URL: ";
251
 
        MSOpenTable     *otab;
252
 
        CSString        *info_request;
253
 
        CSString        *ping_request;
254
 
 
255
 
        enter_();
256
 
        self->myException.setErrorCode(0);
257
 
 
258
 
        iOutputStream->clearHeaders();
259
 
        iOutputStream->clearBody();
260
 
        //iOutputStream->setStatus(200); This is done in the send now.
261
 
        
262
 
        parseRequestURI();
263
 
 
264
 
        ping_request = iInputStream->getHeaderValue(MS_PING_REQUEST);
265
 
        if (ping_request) {
266
 
                MSDatabase *db;
267
 
                
268
 
                db = MSDatabase::getDatabase(ping_request, false);
269
 
                if (db) {
270
 
                        push_(db);
271
 
                        if (db->myBlobCloud->cl_getDefaultCloudRef()) {
272
 
                                MSCloudInfo *info = db->myBlobCloud->cl_getCloudInfo();
273
 
                                push_(info);
274
 
                                iOutputStream->addHeader(MS_CLOUD_SERVER, info->getServer());
275
 
                                release_(info);
276
 
                        }
277
 
                        release_(db);
278
 
                }
279
 
                
280
 
                iOutputStream->setStatus(200); 
281
 
                iOutputStream->writeHead();
282
 
                iOutputStream->flush();
283
 
                exit_();
284
 
 
285
 
        }
286
 
        
287
 
        info_request = iInputStream->getHeaderValue(MS_BLOB_INFO_REQUEST);
288
 
        if (info_request) {
289
 
                info_only = (info_request->compare("yes") == 0);
290
 
                info_request->release();
291
 
        }
292
 
        
293
 
  
294
 
        
295
 
        if (iTableURI->length() == 0)
296
 
                goto bad_url;
297
 
        
298
 
 
299
 
        MSBlobURLRec blob;
300
 
 
301
 
        if (iTableURI->equals("favicon.ico")) {
302
 
                iOutputStream->setStatus(200); 
303
 
                writeFile(iTableURI);
304
 
        } else if (PBMSBlobURLTools::couldBeURL(iTableURI->getCString(), &blob)) {  
305
 
                uint64_t size, offset;
306
 
    
307
 
                if ((! info_only) && iInputStream->getRange(&size, &offset)) { 
308
 
                        if (offset >= blob.bu_blob_size) {
309
 
                                iOutputStream->setStatus(416); // Requested range not satisfiable.
310
 
                                iOutputStream->writeHead();
311
 
                                iOutputStream->flush();
312
 
                                exit_();
313
 
                        }
314
 
                        
315
 
                        if (size > (blob.bu_blob_size - offset))
316
 
                                size = blob.bu_blob_size - offset;                              
317
 
 
318
 
                        iOutputStream->setRange(size, offset, blob.bu_blob_size);
319
 
                } else {
320
 
                        size = blob.bu_blob_size;
321
 
                        offset = 0;
322
 
                }
323
 
 
324
 
                if (blob.bu_type == MS_URL_TYPE_BLOB) {
325
 
                        otab = MSTableList::getOpenTableByID(blob.bu_db_id, blob.bu_tab_id);
326
 
                        frompool_(otab);
327
 
                        otab->sendRepoBlob(blob.bu_blob_id, offset, size, blob.bu_auth_code, info_only, iOutputStream);
328
 
                        backtopool_(otab);
329
 
                } else {
330
 
                        MSRepoFile      *repo_file;
331
 
 
332
 
                        if (!(otab = MSTableList::getOpenTableForDB(blob.bu_db_id))) {
333
 
                                char buffer[CS_EXC_MESSAGE_SIZE];
334
 
                                char id_str[12];
335
 
                                
336
 
                                snprintf(id_str, 12, "%"PRIu32"", blob.bu_db_id);
337
 
 
338
 
                                cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Unknown database ID # ");
339
 
                                cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, id_str);
340
 
                                CSException::throwException(CS_CONTEXT, MS_ERR_UNKNOWN_DB, buffer);
341
 
                        }
342
 
                        frompool_(otab);
343
 
                        repo_file = otab->getDB()->getRepoFileFromPool(blob.bu_tab_id, false);
344
 
                        frompool_(repo_file);
345
 
                        repo_file->sendBlob(otab, blob.bu_blob_id, offset, size, blob.bu_auth_code, true, info_only, iOutputStream);
346
 
                        backtopool_(repo_file);
347
 
                        backtopool_(otab);
348
 
                }
349
 
        } 
350
 
        else { 
351
 
#ifdef HAVE_ALIAS_SUPPORT
352
 
 
353
 
                CSString        *db_name;
354
 
                CSString        *alias;
355
 
                MSDatabase * db;
356
 
                uint32_t repo_id;
357
 
                uint64_t blob_id;
358
 
                
359
 
                db_name = iTableURI->left("/");
360
 
                push_(db_name);
361
 
                alias = iTableURI->right("/");
362
 
                push_(alias);
363
 
 
364
 
                if (db_name->length() == 0 || alias->length() == 0 || alias->length() > BLOB_ALIAS_LENGTH) 
365
 
                        goto bad_url;
366
 
                
367
 
                if (!(otab = MSTableList::getOpenTableForDB(MSDatabase::getDatabaseID(db_name->getCString(), true)))) {
368
 
                        char buffer[CS_EXC_MESSAGE_SIZE];
369
 
 
370
 
                        cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Unknown database: ");
371
 
                        cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, db_name->getCString());
372
 
                        CSException::throwException(CS_CONTEXT, MS_ERR_UNKNOWN_DB, buffer);
373
 
                }
374
 
                frompool_(otab);
375
 
 
376
 
                db = otab->getDB();
377
 
                
378
 
                // lookup the blob alias in the database.
379
 
                if (!db->findBlobWithAlias(alias->getCString(), &repo_id, &blob_id)) {
380
 
                        char buffer[CS_EXC_MESSAGE_SIZE];
381
 
 
382
 
                        cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Unknown alias: ");
383
 
                        cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, alias->getCString());
384
 
                        CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, buffer);
385
 
                }
386
 
                        
387
 
                MSRepoFile *repo_file = db->getRepoFileFromPool(repo_id, false);
388
 
                
389
 
                frompool_(repo_file);
390
 
                repo_file->sendBlob(otab, blob_id, 0, false, info_only, iOutputStream);
391
 
                backtopool_(repo_file); 
392
 
                        
393
 
                backtopool_(otab);              
394
 
                
395
 
                release_(alias);
396
 
                release_(db_name);
397
 
 
398
 
#else
399
 
                char buffer[CS_EXC_MESSAGE_SIZE];
400
 
 
401
 
                cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Bad PBMS BLOB URL: ");
402
 
                cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, iTableURI->getCString());
403
 
                CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, buffer);
404
 
#endif
405
 
        }
406
 
        
407
 
 
408
 
        exit_();
409
 
 
410
 
        bad_url:
411
 
        char buffer[CS_EXC_MESSAGE_SIZE];
412
 
 
413
 
        cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, bad_url_comment);
414
 
        cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, iInputStream->getRequestURI()->getCString());
415
 
        CSException::throwException(CS_CONTEXT, MS_ERR_INCORRECT_URL, buffer);
416
 
        exit_();
417
 
}
418
 
 
419
 
void MSConnectionHandler::handlePut()
420
 
{
421
 
        MSOpenTable *otab = NULL;
422
 
        uint32_t        db_id = 0, tab_id;
423
 
 
424
 
        enter_();
425
 
        self->myException.setErrorCode(0);
426
 
 
427
 
        iOutputStream->clearHeaders();
428
 
        iOutputStream->clearBody();
429
 
        iOutputStream->setStatus(200);
430
 
        
431
 
        parseRequestURI();
432
 
        if (iTableURI->length() != 0)
433
 
                MSDatabase::convertTablePathToIDs(iTableURI->getCString(), &db_id, &tab_id, true);
434
 
 
435
 
 
436
 
        if ((!db_id) || !(otab = MSTableList::getOpenTableByID(db_id, tab_id))) {
437
 
                char buffer[CS_EXC_MESSAGE_SIZE];
438
 
 
439
 
                cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Incorrect URL: ");
440
 
                cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, iInputStream->getRequestURI()->getCString());
441
 
                CSException::throwException(CS_CONTEXT, MS_ERR_INCORRECT_URL, buffer);
442
 
        }
443
 
        frompool_(otab);
444
 
        
445
 
        uint64_t                        blob_len, cloud_blob_len = 0;
446
 
        PBMSBlobURLRec  bh;
447
 
        size_t                  handle_len;
448
 
        uint16_t                        metadata_size = 0; 
449
 
        CSStringBuffer  *metadata;
450
 
        
451
 
        new_(metadata, CSStringBuffer(80));
452
 
        push_(metadata);
453
 
        
454
 
         if (! iInputStream->getContentLength(&blob_len)) {
455
 
                CSException::throwException(CS_CONTEXT, CS_ERR_MISSING_HTTP_HEADER, "Missing content length header");
456
 
         }
457
 
         
458
 
        
459
 
        // Collect the meta data.
460
 
        for (uint32_t i = 0; i < iInputStream->numHeaders(); i++) {
461
 
                CSHeader *header = iInputStream->getHeader(i);
462
 
                const char *name = header->getNameCString();
463
 
                
464
 
                push_(header);
465
 
                
466
 
                if (!strcmp(name, MS_BLOB_SIZE)) { // The actual BLOB data size if it is being stored in a cloud.
467
 
                        sscanf(header->getValueCString(), "%"PRIu64"", &cloud_blob_len);
468
 
                }
469
 
                        
470
 
                if (name && otab->getDB()->isValidHeaderField(name)) {
471
 
                        uint16_t rec_size, name_size, value_size;
472
 
                        const char *value = header->getValueCString();
473
 
                        char *buf;
474
 
                        if (!value)
475
 
                                value = "";
476
 
                                
477
 
                        name_size = strlen(name);
478
 
                        value_size = strlen(value);
479
 
                        
480
 
                        rec_size = name_size + value_size + 2;
481
 
                        metadata->setLength(metadata_size + rec_size);
482
 
                        
483
 
                        buf = metadata->getBuffer(metadata_size);
484
 
                        metadata_size += rec_size;
485
 
                        
486
 
                        memcpy(buf, name, name_size);
487
 
                        buf += name_size;
488
 
                        *buf = 0; buf++;
489
 
                        
490
 
                        memcpy(buf, value, value_size);
491
 
                        buf += value_size;
492
 
                        *buf = 0;
493
 
                }
494
 
                
495
 
                release_(header);
496
 
        }
497
 
        
498
 
        if (blob_len) {
499
 
                char hex_checksum[33];
500
 
                Md5Digest checksum;
501
 
                
502
 
                otab->createBlob(&bh, blob_len, metadata->getBuffer(0), metadata_size, RETAIN(iInputStream), NULL, &checksum);
503
 
 
504
 
                cs_bin_to_hex(33, hex_checksum, 16, checksum.val);
505
 
                iOutputStream->addHeader(MS_CHECKSUM_TAG, hex_checksum);
506
 
        } else { // If there is no BLOB data then the client will send it to the cloud server themselves.
507
 
                if (!cloud_blob_len)
508
 
                        CSException::throwException(CS_CONTEXT, CS_ERR_MISSING_HTTP_HEADER, "Missing BLOB length header for cloud BLOB.");
509
 
                if (otab->getDB()->myBlobType == MS_CLOUD_STORAGE) {
510
 
                        CloudKeyRec cloud_key;
511
 
                        uint32_t signature_time;
512
 
                        char time_str[20];
513
 
                        CloudDB *cloud = otab->getDB()->myBlobCloud;
514
 
                        MSCloudInfo *info;
515
 
                        
516
 
                        
517
 
                        cloud->cl_getNewKey(&cloud_key);
518
 
                        otab->createBlob(&bh, cloud_blob_len, metadata->getBuffer(0), metadata_size, NULL, &cloud_key);
519
 
                        
520
 
                        CSString *signature;
521
 
                        signature = cloud->cl_getSignature(&cloud_key, iInputStream->getHeaderValue("Content-Type"), &signature_time);
522
 
                        push_(signature);
523
 
                        
524
 
                        info = cloud->cl_getCloudInfo(cloud_key.cloud_ref);
525
 
                        push_(info);
526
 
                        iOutputStream->addHeader(MS_CLOUD_SERVER, info->getServer());
527
 
                        iOutputStream->addHeader(MS_CLOUD_BUCKET, info->getBucket());
528
 
                        iOutputStream->addHeader(MS_CLOUD_KEY, info->getPublicKey());
529
 
                        iOutputStream->addHeader(MS_CLOUD_OBJECT_KEY, cloud->cl_getObjectKey(&cloud_key));
530
 
                        iOutputStream->addHeader(MS_BLOB_SIGNATURE, signature->getCString());
531
 
                        release_(info);
532
 
                        
533
 
                        release_(signature);
534
 
                        snprintf(time_str, 20, "%"PRIu32"", signature_time);
535
 
                        iOutputStream->addHeader(MS_BLOB_DATE, time_str);
536
 
                        
537
 
                } else {
538
 
                        // If the database is not using cloud storage then the client will
539
 
                        // resend the BLOB data as a normal BLOB when it fails to get the
540
 
                        // expected cloud server infor headers back.
541
 
                        bh.bu_data[0] = 0;
542
 
                }
543
 
        }
544
 
        handle_len = strlen(bh.bu_data);
545
 
        iOutputStream->setContentLength(handle_len);
546
 
 
547
 
        replyPending = false;
548
 
        iOutputStream->writeHead();
549
 
        iOutputStream->write(bh.bu_data, handle_len);
550
 
        iOutputStream->flush();
551
 
 
552
 
        release_(metadata);
553
 
 
554
 
        backtopool_(otab);
555
 
 
556
 
        exit_();
557
 
}
558
 
 
559
 
void MSConnectionHandler::serviceConnection()
560
 
{
561
 
        const char      *method;
562
 
        bool            threadStarted = false;
563
 
 
564
 
        for (;;) {
565
 
                iInputStream->readHead();
566
 
                if (iInputStream->expect100Continue()) {                        
567
 
                        iOutputStream->clearHeaders();
568
 
                        iOutputStream->clearBody();
569
 
                        iOutputStream->setStatus(100);
570
 
                        iOutputStream->setContentLength(0);
571
 
                        iOutputStream->writeHead();
572
 
                        iOutputStream->flush();
573
 
                }
574
 
                
575
 
                if (!(method = iInputStream->getMethod()))
576
 
                        break;
577
 
                if (!threadStarted /* && iInputStream->keepAlive() */) { // Ignore keepalive: Never trust the client!
578
 
                        /* Start another service handler if no threads
579
 
                         * are waiting to listen!
580
 
                         */
581
 
                        threadStarted = true;
582
 
                        if (!MSNetwork::gWaitingToListen)
583
 
                                MSNetwork::startConnectionHandler();
584
 
                }
585
 
                replyPending = true;
586
 
                if (strcmp(method, "GET") == 0)
587
 
                        handleGet(false);
588
 
                else if (strcmp(method, "PUT") == 0 ||
589
 
                        strcmp(method, "POST") == 0)
590
 
                        handlePut();
591
 
                else if (strcmp(method, "HEAD"))
592
 
                        handleGet(true);
593
 
                else
594
 
                        CSException::throwCoreError(CS_CONTEXT, CS_ERR_UNKNOWN_METHOD, method);
595
 
        }
596
 
}
597
 
 
598
 
bool MSConnectionHandler::initializeWork()
599
 
{
600
 
        return true;
601
 
}
602
 
 
603
 
/*
604
 
 * Return false if no connection this thread should quit!
605
 
 */
606
 
bool MSConnectionHandler::doWork()
607
 
{
608
 
        enter_();
609
 
 
610
 
        /* Open a connection: */
611
 
        if (!openStream()) {
612
 
                myMustQuit = true;
613
 
                return_(false);
614
 
        }
615
 
 
616
 
        /* Do the work for the connection: */
617
 
        serviceConnection();
618
 
 
619
 
        /* Close the connection: */
620
 
        close();
621
 
 
622
 
        return_(false);
623
 
}
624
 
 
625
 
void *MSConnectionHandler::completeWork()
626
 
{
627
 
        shuttingDown = true;
628
 
        /* Close the stream, if it was openned. */
629
 
        close();
630
 
 
631
 
        return NULL;
632
 
}
633
 
 
634
 
bool MSConnectionHandler::handleException()
635
 
{
636
 
        if (!myMustQuit) {
637
 
                /* Start another handler if required: */
638
 
                if (!MSNetwork::gWaitingToListen)
639
 
                        MSNetwork::startConnectionHandler();
640
 
        }
641
 
        close();
642
 
        if (!shuttingDown)
643
 
                CSDaemon::handleException();
644
 
        return false;
645
 
}
646
 
 
647