/** * Process the http request line * parse method, URL and version * @param line string to process * @param method * @param URL * @param version */ void Socket::parseRequestLine(const string &line){ syslog(LOG_DEBUG,"Request line :\"%s\"",line.c_str()); method=""; URL=""; version=""; protocol=""; URLPath=""; regmatch_t match[4]; int nomatch=regexec(®RequestLine, line.c_str(),4, match, 0); if(nomatch) throw HttpException(badRequestCode,"Erroneous request line",line); method=line.substr(match[1].rm_so,match[1].rm_eo-match[1].rm_so); syslog(LOG_DEBUG,"method :\"%s\"",method.c_str()); URL=line.substr(match[2].rm_so,match[2].rm_eo-match[2].rm_so); syslog(LOG_DEBUG,"URL :\"%s\"",URL.c_str()); version=line.substr(match[3].rm_so,match[3].rm_eo-match[3].rm_so); syslog(LOG_DEBUG,"version :\"%s\"",version.c_str()); nomatch=regexec(®URL, URL.c_str(),4, match, 0); if(nomatch) throw HttpException(badRequestCode,"Erroneous URL",URL); if(match[1].rm_so>=0) protocol=URL.substr(match[1].rm_so,match[1].rm_eo-match[1].rm_so); URLPath=URL.substr(match[3].rm_so,match[3].rm_eo-match[3].rm_so); }
void Socket::send(const string &data, bool async){ if(closed) return; writeBuffer += data; size_t size=writeBuffer.size(); const unsigned char *s=(const unsigned char *)writeBuffer.data(); syslog(LOG_INFO,"Sending %lu",(long unsigned int)size); size_t offset=0; struct pollfd devices[1]; devices[0].fd=socket; devices[0].events=POLLOUT; const int wait=1; // 1 milisec const int bad=POLLERR|POLLHUP|POLLNVAL; time_t timeLimit=time(NULL)+JAIL_SOCKET_TIMEOUT; time_t fullTimeLimit=time(NULL)+JAIL_SOCKET_REQUESTTIMEOUT; while(true){ int res=poll(devices,1,wait); if(res==-1) { throw HttpException(internalServerErrorCode ,"Error poll writing data"); //Error } if(res==0 && async) break; //async write Nothing to do if(res==0) continue; //Nothing to do time_t currentTime=time(NULL); if(currentTime>timeLimit || currentTime>fullTimeLimit){ syslog(LOG_ERR,"Socket write timeout"); throw requestTimeoutCode; } if(devices[0].revents & POLLOUT){ //Write to net size_t toWrite=JAIL_NET_BUFFER_SIZE; if(toWrite>size-offset) toWrite=size-offset; int sizeWritten=netWrite(s+offset,toWrite); if(sizeWritten <0) { throw HttpException(internalServerErrorCode ,"Socket write data error"); }if(sizeWritten == 0){ closed=true; break; } else{ offset += sizeWritten; timeLimit=currentTime+JAIL_SOCKET_TIMEOUT; //Reset timeout } } if(devices[0].revents & POLLHUP){ //socket close closed=true; syslog(LOG_INFO,"POLLHUP"); break; } if(devices[0].revents & bad) { syslog(LOG_ERR,"Error writing http data %m"); throw HttpException(internalServerErrorCode ,"Socket write data error"); } if(offset>=size) break; } writeBuffer.erase(0,offset); syslog(LOG_INFO,"Send %lu",(long unsigned int)offset); }
/** * Process http request headers (until CRLFCRLF) * Check request line and parse headers * @param input lines that form the request line and headers */ void HttpJailServer::validateRequest(string path){ if(socket->getMethod() != "POST"){ throw HttpException(notImplementedCode, "http METHOD not implemented",socket->getMethod()); } if(path == "") path="/"; string URLPath=socket->getURLPath(); if(URLPath == "") URLPath="/"; if(path != URLPath){ throw HttpException(notFoundCode ,"http request URL path not found" , "expected '"+socket->getURLPath()+"' found '"+path+"'"); } }
Filter::Result DeniedMethodsFilter::Process(CGI *cgi) { if (_methods.find(cgi->_SERVER["REQUEST_METHOD"]) != _methods.end()) { throw HttpException(405); } return kResultPass; }
/** * Process one header * Parse header and save it in header map * @param line header to process */ void Socket::parseHeader(const string &line){ syslog(LOG_INFO,"Header :\"%s\"",line.c_str()); regmatch_t match[3]; int nomatch=regexec(®Header, line.c_str(),3, match, 0); if(nomatch){ char errorm[100]; regerror(nomatch,®Header,errorm,100); syslog(LOG_DEBUG,"No match %d: %s",nomatch,errorm); throw HttpException(badRequestCode,"Erroneous header",line); } string field=Util::toUppercase(line.substr(match[1].rm_so,match[1].rm_eo-match[1].rm_so)); string value=line.substr(match[2].rm_so,match[2].rm_eo-match[2].rm_so); headers[field]= value; }
string HttpJailServer::receive(){ if(socket->getHeader("Expect")== "100-continue"){ sendCode(continueCode); } int sizeToRead=atoi(socket->getHeader("Content-Length").c_str()); if(sizeToRead != 0){ if(sizeToRead > JAIL_REQUEST_MAX_SIZE){ throw HttpException(requestEntityTooLargeCode ,"http Request size too large" ,socket->getHeader("Content-Length")); } return socket->receive(sizeToRead); } return ""; }
void HttpResponseFile::InitContent(std::string filename) { itsIFile.open(filename.c_str(), std::ios_base::in | std::ios_base::binary); if (!itsIFile.good()) { throw HttpException("Bad file given", http::Status::NOT_FOUND); } // get length of file: itsIFile.seekg(0, std::ios::end); int length = itsIFile.tellg(); itsIFile.seekg(0, std::ios::beg); itsContent.resize(length); std::copy(std::istreambuf_iterator<char>(itsIFile), std::istreambuf_iterator<char>(), itsContent.begin()); DBG << "Content of the file=" << getContent(); }
string Socket::receive(int sizeToReceive){ //=0 async read if(closed) { string ret=readBuffer; readBuffer=""; if(ret.size()){ syslog(LOG_INFO,"Received %lu",(long unsigned int)ret.size()); } return ret; } if(header.size()==0) sizeToReceive = JAIL_HEADERS_SIZE_LIMIT; if(sizeToReceive){ syslog(LOG_INFO,"Receiving until %d bytes",sizeToReceive); } //If already read, return data if(sizeToReceive>0 && readBuffer.size()>=sizeToReceive && header.size()!=0){ string ret = readBuffer.substr(0,sizeToReceive); readBuffer.erase(0,sizeToReceive); return ret; } struct pollfd devices[1]; devices[0].fd=socket; devices[0].events=POLLIN; const int MAX=JAIL_NET_BUFFER_SIZE; char buf[MAX]; const int wait=10; // 10 milisec const int bad=POLLERR|POLLNVAL; time_t timeLimit=time(NULL)+JAIL_SOCKET_TIMEOUT; time_t fullTimeLimit=time(NULL)+JAIL_SOCKET_REQUESTTIMEOUT; while(true){ int res=poll(devices,1,wait); if(res==-1) { syslog(LOG_INFO,"poll fail reading %m"); throw HttpException(internalServerErrorCode ,"Error poll reading data"); //Error } time_t currentTime=time(NULL); if(currentTime>timeLimit || currentTime>fullTimeLimit){ if(sizeToReceive==0){ syslog(LOG_DEBUG,"Socket read timeout, closed connection?"); return ""; }else throw HttpException(requestTimeoutCode ,"Socket read timeout"); } if(res==0 && sizeToReceive==0) break; //Nothing to read if(res==0) continue; //Nothing to do syslog(LOG_DEBUG,"poll return: %d",res); if(devices[0].revents & POLLIN){ //Read from net int sizeRead=netRead(buf,MAX); if(sizeRead >0) { string sread(buf,sizeRead); if(sread.size()!=sizeRead){ syslog(LOG_ERR,"read net decode error"); } readBuffer += sread; if(header.size()==0){ size_t pos; if((pos=readBuffer.find("\r\n\r\n")) != string::npos){ header=readBuffer.substr(0,pos+4); syslog(LOG_INFO,"Received header %lu",(long unsigned int)pos+4); processHeaders(header); readBuffer.erase(0,pos+4); return ""; //End of process }else if(readBuffer.size()>JAIL_HEADERS_SIZE_LIMIT){ throw HttpException(requestEntityTooLargeCode,"Http headers too large"); } }else if(sizeToReceive==0 || readBuffer.size()>=sizeToReceive){ //Receive complete break; } timeLimit=currentTime+JAIL_SOCKET_TIMEOUT; //Reset timeout } else if(sizeRead<0){ throw HttpException(badRequestCode ,"Error reading data"); } else { syslog(LOG_INFO,"sizeRead==0"); closed=true; break; } } if(devices[0].revents & POLLHUP){ //socket close closed=true; syslog(LOG_INFO,"POLLHUP"); break; } if(devices[0].revents & bad) { throw HttpException(internalServerErrorCode ,"Error reading data"); } } string ret=readBuffer; readBuffer=""; if(ret.size()){ syslog(LOG_INFO,"Received %lu",(long unsigned int)ret.size()); } return ret; }
void Server::ServeFile(const std::string& fileName,HttpServerContext* context,bool download) { long long size=FileUtils::GetFileSize(fileName); if(size==-1) throw HttpException(HttpNotFound,"Requested file not found."); time_t modifyTime=FileUtils::GetFileModifyTime(fileName); if((context->requestHeader.modifyTime!=0)&&(modifyTime<=context->requestHeader.modifyTime)) { context->responseHeader.result=HttpNotModified; return; } context->responseHeader.modifyTime=modifyTime; File in(fileName,false); long long contentLength; if(context->requestHeader.rangeFrom==-1) { contentLength=size; context->responseHeader.contentLength=size; } else { if(context->requestHeader.rangeTo==-1) context->requestHeader.rangeTo=size-1; contentLength=context->requestHeader.rangeTo-context->requestHeader.rangeFrom+1; context->responseHeader.contentLength=contentLength; context->responseHeader.rangeFrom=context->requestHeader.rangeFrom; context->responseHeader.rangeTo=context->requestHeader.rangeTo; context->responseHeader.rangeTotal=size; in.Seek(context->requestHeader.rangeFrom); } if(!download) { int slashpos=fileName.find('/'); string t; if(slashpos!=string::npos) t=fileName.substr(slashpos+1); else t=fileName; int dotpos=t.rfind('.'); if(dotpos!=string::npos) { string ext=t.substr(dotpos+1); context->responseHeader.contentType=Util::MimeType(ext); } } else context->responseHeader.contentType="application/octet-stream"; context->SendResponseHeader(); char buf[1024]; while(contentLength>0) { int br; if(contentLength<sizeof(buf)) br=static_cast<int>(contentLength); else br=sizeof(buf); in.Read(buf,br); context->Write(buf,br); contentLength-=br; } }