00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 # include "QcjHttpService.h"
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 QcjHttpService::QcjHttpService(int socketDescripter, QObject *parent, int max_req, QStringList *extraMethods, long ttl) :
00067 QThread(parent)
00068 {
00069 printf("QcjHttpService::QcjHttpService(%s): Enter, socknum = %d\n", qPrintable(QString::number(currentThreadId())), socknum);
00070 fflush(stdout);
00071 if ( socketDescripter >= 0 )
00072 {
00073 socknum = socketDescripter;
00074
00075 timeToLive = ttl;
00076 maxRequests = max_req;
00077 methods << "GET";
00078 methods << "POST";
00079 methods << "PUT";
00080 methods << "HEAD";
00081 methods << "TRACE";
00082 methods << "OPTIONS";
00083 methods << "DELETE";
00084 if ( extraMethods != 0 )
00085 methods << *extraMethods;
00086
00087 if ((sock = new QTcpSocket()) == NULL)
00088 {
00089 printf("QcjHttpService::QcjHttpService(%s): Error creating socket\n", qPrintable(QString::number(currentThreadId())));
00090 fflush(stdout);
00091 return;
00092 }
00093 printf("QcjHttpService::QcjHttpService(%s): setting descripter\n", qPrintable(QString::number(currentThreadId())));
00094 fflush(stdout);
00095 if (! sock->setSocketDescriptor(socknum)) {
00096 printf("QcjHttpService::QcjHttpService(%s): Exit in error\n", qPrintable(QString::number(currentThreadId())));
00097 fflush(stdout);
00098 return;
00099 }
00100 printf("QcjHttpService::QcjHttpService(%s): Connecting signals and handles\n", qPrintable(QString::number(currentThreadId())));
00101 fflush(stdout);
00102 connect(sock, SIGNAL(readyRead()), this, SLOT(haveData()), Qt::QueuedConnection);
00103 connect(sock, SIGNAL(disconnected()), this, SLOT(haveDisconnect()), Qt::QueuedConnection);
00104 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(haveError(QAbstractSocket::SocketError)));
00105
00106 inBuffer.setBuffer(&inArray);
00107 inBuffer.open(QBuffer::ReadWrite);
00108 inStream.setDevice(&inBuffer);
00109
00110 inBody = false;
00111 request = 0;
00112 }
00113 printf("QcjHttpService::QcjHttpService(%s): exit\n", qPrintable(QString::number(currentThreadId())));
00114 fflush(stdout);
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 void QcjHttpService::run()
00127 {
00128 QString method;
00129 QString path;
00130 QString version;
00131 bool err = false;
00132
00133 printf("QcjHttpService::run(%s): Enter, socknum = %d\n", qPrintable(QString::number(currentThreadId())), socknum);
00134 fflush(stdout);
00135
00136 ttlTimer = new QTimer;
00137 connect(ttlTimer, SIGNAL(timeout()), this, SLOT(haveTimeOut()));
00138 ttlTimer->start(timeToLive);
00139
00140 errTimer = new QTimer;
00141 connect(errTimer, SIGNAL(timeout()), this, SLOT(haveTimeOut()));
00142
00143 exitFlag = false;
00144 myThreadId = currentThreadId();
00145 lineBuffer.clear();
00146 bufLock.lock();
00147 while (1)
00148 {
00149 if ( exitFlag )
00150 {
00151 printf("QcjHttpService::run(%s): exit flag set, exiting!\n", qPrintable(QString::number(currentThreadId())));
00152 fflush(stdout);
00153 clearLocks();
00154 printf("QcjHttpService::run(%s): Calling return\n", qPrintable(QString::number(currentThreadId())));
00155 fflush(stdout);
00156 return;
00157 }
00158
00159 if ( inArray.size() == 0 )
00160 {
00161 printf("QcjHttpService::run(%s): waiting input, sock %d\n", qPrintable(QString::number(currentThreadId())), socknum);
00162 fflush(stdout);
00163 haveInput.wait(&bufLock);
00164 }
00165
00166 if ( exitFlag )
00167 {
00168 printf("QcjHttpService::run(%s): exit flag set, exiting!\n", qPrintable(QString::number(currentThreadId())));
00169 fflush(stdout);
00170 clearLocks();
00171 printf("QcjHttpService::run(%s): Calling return\n", qPrintable(QString::number(currentThreadId())));
00172 fflush(stdout);
00173 return;
00174 }
00175
00176 if ( ! inBody )
00177 {
00178 printf("QcjHttpService::run(%s): Not in body, have %d bytes available\n", qPrintable(QString::number(currentThreadId())), inArray.size());
00179 fflush(stdout);
00180
00181 while ( inArray.size() > 0 )
00182 {
00183 char ch;
00184
00185
00186 ch = *(inArray.data());
00187 inArray.remove(0, 1);
00188 bufLock.unlock();
00189
00190
00191 lineBuffer += ch;
00192 if ( ch == '\0' )
00193 {
00194 printf("QcjHttpService::run(%s): have null byte\n", qPrintable(QString::number(currentThreadId())));
00195 fflush(stdout);
00196 bufLock.lock();
00197
00198
00199 continue;
00200 }
00201
00202 if ( ch == '\n' )
00203 {
00204 printf("QcjHttpService::run(%s): Have line: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(lineBuffer));
00205 fflush(stdout);
00206 errTimer->start(500);
00207 QString in;
00208 in.append(lineBuffer);
00209 lineBuffer.clear();
00210 in.remove('\r');
00211 in.remove('\n');
00212 if ( request == 0 )
00213 {
00214 printf("QcjHttpService::run(%s): Processing request\n", qPrintable(QString::number(currentThreadId())));
00215 fflush(stdout);
00216 request = new QMap<QString, QVariant>;
00217
00218 method.clear();
00219 path.clear();
00220 version.clear();
00221 QStringList sl = in.split(" ");
00222
00223 printf("QcjHttpService::run(%s): Have %d request parts\n", qPrintable(QString::number(currentThreadId())), sl.size());
00224 fflush(stdout);
00225
00226 if ( sl.size() > 0 )
00227 method = sl[0];
00228 if ( sl.size() > 1 )
00229 path = sl[1];
00230 if ( sl.size() > 2 )
00231 version = sl[2];
00232 else
00233 err = true;
00234
00235 printf("QcjHttpService::run(%s): method = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(method));
00236 fflush(stdout);
00237 if ( err )
00238 {
00239 printf("QcjHttpService::run(%s): Returning error and exiting\n", qPrintable(QString::number(currentThreadId())));
00240 fflush(stdout);
00241 errorResponse(QcjHttpService::BadRequest, "Malformed Request");
00242 delete request;
00243 request = 0;
00244 }
00245 else if ( methods.contains(method) )
00246 {
00247 printf("QcjHttpService::run(%s): Have valid method\n", qPrintable(QString::number(currentThreadId())));
00248 fflush(stdout);
00249 QString args("");
00250 QString resource("");
00251 QStringList reslist = path.split("?");
00252 if ( reslist.size() == 2 )
00253 {
00254 resource = reslist[0];
00255 args = reslist[1];
00256 }
00257 else
00258 resource = path;
00259
00260 request->insert("Resource", resource);
00261 request->insert("Arguments", args);
00262 request->insert("Method", method);
00263 request->insert("Version", version);
00264 request->insert("Content-Length", QVariant((qlonglong)0));
00265 }
00266 else
00267 {
00268 errorResponse(QcjHttpService::BadRequest, "Invalid method: " + method);
00269 delete request;
00270 request = 0;
00271 }
00272 }
00273 else if ( in.size() > 0 )
00274 {
00275 QRegExp re("(.+): (.*)");
00276 re.setMinimal(true);
00277
00278 printf("QcjHttpService::run(%s): Testing for tag\n", qPrintable(QString::number(currentThreadId())));
00279 fflush(stdout);
00280 QStringList sl = in.split(": ");
00281 if ( sl.size() == 1 )
00282 {
00283 sl = in.split(":");
00284 }
00285 if ( sl.size() == 2 )
00286 {
00287 QString tag = sl[0];
00288 QString val = sl[1];
00289 printf("QcjHttpService::run(%s): tag = |%s|, val = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(tag), qPrintable(val));
00290 fflush(stdout);
00291 bool isint;
00292 long x = val.toLong(&isint);
00293 if ( isint )
00294 request->insert(tag, (qlonglong)x);
00295 else
00296 request->insert(tag, val);
00297 }
00298 }
00299 else
00300 {
00301 expectingBytes = request->value("Content-Length").toLongLong();
00302 printf("QcjHttpService::run(%s): content length = %ld\n", qPrintable(QString::number(currentThreadId())), (long)expectingBytes);
00303 fflush(stdout);
00304 if ( expectingBytes == 0 )
00305 {
00306 printf("QcjHttpService::run(%s): Not getting any data\n", qPrintable(QString::number(currentThreadId())));
00307 fflush(stdout);
00308 QMap<QString, QVariant> response;
00309 errTimer->stop();
00310 printf("QcjHttpService::run(%s): Calling processRequest()\n", qPrintable(QString::number(currentThreadId())));
00311 fflush(stdout);
00312 processRequest(request, &response);
00313 processResponse(response);
00314 printf("QcjHttpService::run(%s): Clearing bufs etc.()\n", qPrintable(QString::number(currentThreadId())));
00315 fflush(stdout);
00316 delete request;
00317 request = 0;
00318 }
00319 else
00320 {
00321 inBody = true;
00322 break;
00323 }
00324 }
00325 }
00326
00327
00328 bufLock.lock();
00329 }
00330 }
00331
00332 if ( inBody && inArray.count() > 0 )
00333 {
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 }
00356 printf("QcjHttpService::run(%s): waiting for more data to come in\n", qPrintable(QString::number(currentThreadId())));
00357 fflush(stdout);
00358 }
00359 printf("QcjHttpService::run(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00360 fflush(stdout);
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370 void QcjHttpService::haveData()
00371 {
00372 printf("QcjHttpService::haveData(%s): Enter bytes avail = %ld\n", qPrintable(QString::number(currentThreadId())), (long)sock->bytesAvailable());
00373 fflush(stdout);
00374 while (sock->bytesAvailable() > 0)
00375 {
00376 char buf[1024];
00377 int bytes;
00378 if ( (bytes = sock->read(buf, sizeof(buf))) > 0 )
00379 {
00380 bufLock.lock();
00381 printf("QcjHttpService::haveData(%s): appending %d bytes () to inArray\n", qPrintable(QString::number(currentThreadId())), bytes);
00382 fflush(stdout);
00383
00384 inArray.append(QByteArray(buf, bytes));
00385 printf("QcjHttpService::haveData(%s): inArray has %d bytes available\n", qPrintable(QString::number(currentThreadId())), inArray.size());
00386 fflush(stdout);
00387 bufLock.unlock();
00388 }
00389 else if ( bytes < 0 )
00390 return;
00391 }
00392 printf("QcjHttpService::haveData(%s): waking thread\n", qPrintable(QString::number(currentThreadId())));
00393 fflush(stdout);
00394 haveInput.wakeAll();
00395 printf("QcjHttpService::haveData(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00396 fflush(stdout);
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 void QcjHttpService::processResponse(QMap<QString, QVariant> rsp)
00409 {
00410 printf("QcjHttpService::processResponse(%s): Enter\n", qPrintable(QString::number(currentThreadId())));
00411 fflush(stdout);
00412 sendResponse(&rsp);
00413
00414 printf("QcjHttpService::processResponse(%s): maxRequests = %d\n", qPrintable(QString::number(currentThreadId())), maxRequests);
00415 fflush(stdout);
00416 if ( --maxRequests == 0)
00417 {
00418 printf("QcjHttpService::processResponse(%s): terminating socket connection\n", qPrintable(QString::number(currentThreadId())));
00419 fflush(stdout);
00420 emit closeSocket(sock);
00421 }
00422 printf("QcjHttpService::processResponse(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00423 fflush(stdout);
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433 void QcjHttpService::sendResponse(QMap<QString, QVariant> *rsp)
00434 {
00435 QByteArray body;
00436
00437 printf("QcjHttpService::sendResponse(%s): Enter\n", qPrintable(QString::number(currentThreadId())));
00438 fflush(stdout);
00439
00440 QMapIterator<QString, QVariant> i(*rsp);
00441 while (i.hasNext())
00442 {
00443 i.next();
00444 if ( i.key() == "Request-Body" )
00445 printf("DbPhotoService::sendResponse(%s): rsp: |%s| %d length\n", qPrintable(QString::number(currentThreadId())), qPrintable(i.key()), i.value().toByteArray().size());
00446 else
00447 printf("DbPhotoService::sendResponse(%s): rsp: |%s| = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(i.key()), qPrintable(i.value().toString()));
00448 fflush(stdout);
00449 }
00450
00451 if ( rsp->value("Status").toInt() != QcjHttpService::OK )
00452 {
00453 printf("QcjHttpService::sendResponse(%s): Sending error response\n", qPrintable(QString::number(currentThreadId())));
00454 fflush(stdout);
00455 emit send(sock, qPrintable("HTTP/1.1 " + rsp->value("Status").toString() + " " + rsp->value("StatusString").toString() + "\r\n"));
00456 printf("QcjHttpService::sendResponse(%s): returning\n", qPrintable(QString::number(currentThreadId())));
00457 fflush(stdout);
00458 return;
00459 }
00460
00461 printf("QcjHttpService::sendResponse(%s): Sending regular response\n", qPrintable(QString::number(currentThreadId())));
00462 fflush(stdout);
00463 emit send(sock, qPrintable("HTTP/1.1 " + rsp->value("Status").toString() + " " + rsp->value("StatusString").toString() + "\r\n"));
00464
00465 printf("QcjHttpService::sendResponse(%s): Iterating headers\n", qPrintable(QString::number(currentThreadId())));
00466 fflush(stdout);
00467 QMapIterator<QString, QVariant> it(*rsp);
00468 while (it.hasNext())
00469 {
00470 it.next();
00471 printf("QcjHttpService::sendResponse(%s): fetching key\n", qPrintable(QString::number(currentThreadId())));
00472 fflush(stdout);
00473 QString tag = it.key();
00474 if ( tag == "Request-Body" )
00475 {
00476 printf("QcjHttpService::sendResponse(%s): Setting body\n", qPrintable(QString::number(currentThreadId())));
00477 fflush(stdout);
00478 body = it.value().toByteArray();
00479 }
00480 else
00481 {
00482 printf("QcjHttpService::sendResponse(%s): Sending tag\n", qPrintable(QString::number(currentThreadId())));
00483 fflush(stdout);
00484 QString val = it.value().toString();
00485 emit send(sock, qPrintable(tag + ": " + val + "\r\n"));
00486 }
00487 }
00488 printf("QcjHttpService::sendResponse(%s): Sending body\n", qPrintable(QString::number(currentThreadId())));
00489 fflush(stdout);
00490
00491 if ( body.size() > 0 )
00492 {
00493 emit send(sock, "\r\n");
00494 emit send(sock, body);
00495 }
00496 printf("QcjHttpService::sendResponse(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00497 fflush(stdout);
00498 }
00499
00500
00501
00502
00503
00504
00505
00506 void QcjHttpService::haveTimeout()
00507 {
00508 errorResponse(QcjHttpService::RequestTimeout, "You're too slow!");
00509 }
00510
00511
00512
00513
00514
00515
00516 void QcjHttpService::haveError(QAbstractSocket::SocketError)
00517 {
00518 printf("QcjHttpService::haveError(%s): Enter, flagging thread %s to exit\n", qPrintable(QString::number(currentThreadId())), qPrintable(QString::number(myThreadId)));
00519 fflush(stdout);
00520 exitFlag = true;
00521 haveInput.wakeAll();
00522 printf("QcjHttpService::haveError(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00523 fflush(stdout);
00524 }
00525
00526
00527
00528
00529
00530
00531 void QcjHttpService::haveDisconnect()
00532 {
00533 printf("QcjHttpService::haveDisconnect(%s): Enter, flagging thread %s to exit\n", qPrintable(QString::number(currentThreadId())), qPrintable(QString::number(myThreadId)));
00534 fflush(stdout);
00535 exitFlag = true;
00536 haveInput.wakeAll();
00537 printf("QcjHttpService::haveDisconnect(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00538 fflush(stdout);
00539 }
00540
00541
00542
00543
00544
00545
00546 void QcjHttpService::errorResponse(enum ErrorCodes ec, QString msg)
00547 {
00548 QMap<QString, QVariant> responses;
00549 responses.insert("Status", QString::number(ec));
00550 responses.insert("StatusString", msg);
00551 sendResponse(&responses);
00552 emit closeSocket(sock);
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562 QMap<QString, QString> QcjHttpService::parseArguments(QString args)
00563 {
00564 QMap<QString, QString> rv;
00565 QStringList sl = args.split("&");
00566 for (int x = 0; x < sl.size(); x++)
00567 {
00568 QStringList sl1 = sl[x].split("=");
00569 if ( sl1.size() == 2 )
00570 rv.insert(sl1[0], sl1[1]);
00571 }
00572 return(rv);
00573 }
00574
00575
00576
00577
00578
00579
00580
00581 void QcjHttpService::haveTimeOut()
00582 {
00583 printf("QcjHttpService::haveTimeOut(%s): Enter\n", qPrintable(QString::number(currentThreadId())));
00584 fflush(stdout);
00585 emit closeSocket(sock);
00586 printf("QcjHttpService::haveTimeOut(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00587 fflush(stdout);
00588 }
00589
00590
00591
00592
00593
00594
00595
00596
00597