#include #include #include #include #include "HttpConnection.h" #include "../Socket.h" #include "HttpStatusCode.h" #include "Http.h" HttpConnection::HttpConnection(Socket *socket) { this->socket = socket; this->request = new HttpRequest(socket); this->response = new HttpResponse(); microsStart = getMicros(); response->setVersion("1.1"); response->setField("Server", "Necronda/3.0"); } void HttpConnection::respond(int statuscode) { if (statuscode >= 400 && statuscode < 600) { respond(statuscode, "" + to_string(statuscode) + " " + ::getStatusCode(statuscode).message + "

" + to_string(statuscode) + " " + ::getStatusCode(statuscode).message + "

" + ((request->isExistingField("Host")) ? (request->isExistingField("Referer") && request->getField("Referer").find(request->getField("Host")) != string::npos) ? "

Go back to the last page you visited: getField("Referer") + "\">" + request->getField("Referer") + "

" : "

Go back to the home page of getField("Host") + "/\">" + request->getField("Host") + "

" : "") + "
\r\n" ); } else { respond(statuscode, ""); } } void HttpConnection::respond(int statuscode, string payload) { response->setStatusCode(statuscode); response->setField("Date", getHttpDate()); response->setField("Content-Length", to_string(payload.length())); response->sendHeader(socket); socket->send(std::move(payload)); } void HttpConnection::respond(int statuscode, FILE *file, bool compress, long start, long end) { response->setStatusCode(statuscode); response->setField("Transfer-Encoding", "chunked"); response->setField("Date", getHttpDate()); long shouldTransfer; long transfered = 0; fseek(file, 0, SEEK_END); long len = ftell(file); if (start != -1 && end != -1) { fseek(file, start, SEEK_SET); response->setField("Content-Length", to_string(end - start + 1)); shouldTransfer = end - start + 1; compress = false; } else { fseek(file, 0, SEEK_SET); shouldTransfer = len; if (len >= 0 && !compress) { response->setField("Content-Length", to_string(len)); } } if (compress) { response->setField("Content-Encoding", "deflate"); } response->sendHeader(socket); if (compress) { int level = 1; int ret, flush; unsigned have; z_stream strm; unsigned char in[CPPNET_CHUNK]; unsigned char out[CPPNET_CHUNK]; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; ret = deflateInit(&strm, level); if (ret != Z_OK) { throw (char *) "Unable to open file"; } do { strm.avail_in = (uInt) fread(in, 1, CPPNET_CHUNK, file); if (ferror(file)) { (void) deflateEnd(&strm); throw (char *) strerror(errno); } flush = feof(file) ? Z_FINISH : Z_NO_FLUSH; strm.next_in = in; do { strm.avail_out = CPPNET_CHUNK; strm.next_out = out; ret = deflate(&strm, flush); assert(ret != Z_STREAM_ERROR); have = CPPNET_CHUNK - strm.avail_out; if (have != 0) { char buffer[64]; sprintf(buffer, "%X\r\n", have); socket->send(buffer); socket->send((const char *) out, have); socket->send("\r\n"); } } while (strm.avail_out == 0); assert(strm.avail_in == 0); } while (flush != Z_FINISH); assert(ret == Z_STREAM_END); socket->send("0\r\n\r\n"); deflateEnd(&strm); } else { char buffer[CPPNET_CHUNK]; char buff[64]; while (true) { unsigned long size = fread(buffer, 1, (size_t) ((CPPNET_CHUNK > (shouldTransfer - transfered) && shouldTransfer > 0) ? (shouldTransfer - transfered) : CPPNET_CHUNK), file); transfered += size; sprintf(buff, "%lX\r\n", size); socket->send(buff); socket->send((const char *) buffer, size); socket->send("\r\n"); if (size == 0) { break; } } } } string HttpConnection::getField(string index) { return request->getField(std::move(index)); } string HttpConnection::getPath() { return request->getPath(); } void HttpConnection::setField(string index, string data) { response->setField(std::move(index), std::move(data)); } bool HttpConnection::isExistingField(string index) { return request->isExistingField(std::move(index)); } string HttpConnection::getMethod() { return request->getMethod(); } long HttpConnection::getDuration() { return getMicros() - microsStart; } HttpStatusCode HttpConnection::getStatusCode() { return response->getStatusCode(); } void HttpConnection::redirect(int statuscode, string location) { setField("Location", std::move(location)); respond(statuscode, ""); } string HttpConnection::getResponseField(string index) { return response->getField(std::move(index)); } bool HttpConnection::isExistingResponseField(string index) { return response->isExistingField(std::move(index)); } string HttpConnection::cgiExport() { return request->cgiExport(); } void HttpConnection::removeField(string index) { response->removeField(std::move(index)); }