/** * Tries to construct an HTTP request object from the given string. * @return Returns the object representing the request on success, or NULL if * the string could not be parsed. If set, consumed will be filled with * the amount of data that was consumed from the string to parse the request. */ Request* Request::fromString(const string &str, unsigned int *consumed) { unsigned int cons = 0; //Parse the first line which consists of the request type. size_t firstCRLF = str.find("\r\n"); if (firstCRLF == string::npos) return NULL; string firstLine = str.substr(0, firstCRLF); cons = firstCRLF + 2; size_t methodPos = firstLine.find(" "); if (methodPos == string::npos) return NULL; string method = firstLine.substr(0, methodPos); Type type; if (method == "GET") type = kGET; else if (method == "POST") type = kPOST; else if (method == "DELETE") type = kDELETE; else if (method == "PUT") type = kPUT; else { throw new GenericError(string("Received HTTP request with unknown method '") + method + "'."); } size_t pathPos = firstLine.find(" ", methodPos + 1); if (pathPos == string::npos) return NULL; string path = firstLine.substr(methodPos + 1, pathPos - methodPos - 1); //Parse the header. unsigned int hsConsumed = 0; HeaderSet *hs = HeaderSet::fromString(str.substr(firstCRLF + 2), &hsConsumed); cons += hsConsumed; if (!hs) return NULL; //Read the content. int expectedLength = 0; if (hs->has("Content-Length")) { expectedLength = atoi(hs->get("Content-Length").c_str()); if (expectedLength > str.size() - cons) { return NULL; } } //Create the request object. Request *req = new Request; req->type = type; req->path = path; req->headers = *hs; req->content = str.substr(cons, expectedLength); cons += expectedLength; if (consumed) *consumed = cons; return req; }