2 #include <lib/network/httpd.h>
4 #include <sys/socket.h>
10 eHTTPDataSource::eHTTPDataSource(eHTTPConnection *c): connection(c)
14 eHTTPDataSource::~eHTTPDataSource()
18 void eHTTPDataSource::haveData(void *data, int len)
22 int eHTTPDataSource::doWrite(int)
27 eHTTPError::eHTTPError(eHTTPConnection *c, int errcode): eHTTPDataSource(c), errcode(errcode)
29 eString error="unknown error";
32 case 400: error="Bad Request"; break;
33 case 401: error="Unauthorized"; break;
34 case 403: error="Forbidden"; break;
35 case 404: error="Not found"; break;
36 case 405: error="Method not allowed"; break;
37 case 500: error="Internal server error"; break;
39 connection->code_descr=error;
40 connection->code=errcode;
42 connection->local_header["Content-Type"]=std::string("text/html");
45 int eHTTPError::doWrite(int w)
48 html+="<html><head><title>Error "+eString().setNum(connection->code)+"</title></head>"+
49 "<body><h1>Error "+eString().setNum(errcode)+": "+connection->code_descr+"</h1></body></html>\n";
50 connection->writeBlock(html.c_str(), html.length());
54 eHTTPConnection::eHTTPConnection(int socket, int issocket, eHTTPD *parent, int persistent): eSocket(socket, issocket, parent->ml), parent(parent), persistent(persistent)
57 eDebug("eHTTPConnection");
59 CONNECT(this->readyRead_ , eHTTPConnection::readData);
60 CONNECT(this->bytesWritten_ , eHTTPConnection::bytesWritten);
61 CONNECT(this->error_ , eHTTPConnection::gotError);
62 CONNECT(this->connectionClosed_ , eHTTPConnection::destruct);
63 CONNECT(this->hangup , eHTTPConnection::gotHangup);
67 remotestate=stateRequest;
71 void eHTTPConnection::destruct()
77 eHTTPConnection::eHTTPConnection(eMainloop *ml): eSocket(ml), parent(0), persistent(0)
79 CONNECT(this->readyRead_ , eHTTPConnection::readData);
80 CONNECT(this->bytesWritten_ , eHTTPConnection::bytesWritten);
81 CONNECT(this->error_ , eHTTPConnection::gotError);
82 CONNECT(this->connected_ , eHTTPConnection::hostConnected);
83 CONNECT(this->connectionClosed_ , eHTTPConnection::destruct);
86 remotestate=stateWait;
92 void eHTTPConnection::hostConnected()
97 void eHTTPConnection::start()
99 if (localstate==stateWait)
101 localstate=stateRequest;
106 void eHTTPConnection::gotHangup()
108 if (data && remotestate == stateData)
109 data->haveData(0, 0);
117 localstate=stateWait;
118 remotestate=stateRequest;
120 remote_header.clear();
121 local_header.clear();
124 eHTTPConnection *eHTTPConnection::doRequest(const char *uri, eMainloop *ml, int *error)
129 char *defaultproto="http";
130 std::string proto, host, path;
133 int state=0; // 0 proto, 1 host, 2 port 3 path
140 if (!strncmp(uri, "://", 3))
144 } else if ((*uri=='/') || (*uri==':'))
150 proto.push_back(*uri++);
161 host.push_back(*uri++);
180 path.push_back(*uri++);
191 eDebug("proto: '%s', host '%s', path '%s', port '%d'", proto.c_str(), host.c_str(), path.c_str(), port);
196 eDebug("no host given");
202 if (strcmp(proto.c_str(), "http"))
204 eDebug("invalid protocol (%s)", proto.c_str());
212 eDebug("invalid port");
221 eHTTPConnection *c=new eHTTPConnection(ml);
223 c->requestpath=path.c_str();
224 c->httpversion="HTTP/1.0";
225 c->local_header["Host"]=host;
226 if ((*error=c->connectToHost(host, port))) // already deleted by error
231 void eHTTPConnection::readData()
233 processRemoteState();
236 void eHTTPConnection::bytesWritten(int)
241 int eHTTPConnection::processLocalState()
254 eDebug("processing local state %d", localstate);
260 eDebug("local wait");
267 eDebug("local request");
269 eString req=request+" "+requestpath+" "+httpversion+"\r\n";
270 writeBlock(req.c_str(), req.length());
271 localstate=stateHeader;
272 remotestate=stateResponse;
278 eDebug("local Response");
280 writeString( (httpversion + " " + eString().setNum(code)+" " + code_descr + "\r\n").c_str() );
281 localstate=stateHeader;
282 local_header["Connection"]="close";
287 eDebug("local header");
289 for (std::map<std::string,std::string>::iterator cur=local_header.begin(); cur!=local_header.end(); ++cur)
291 writeString(cur->first.c_str());
293 writeString(cur->second.c_str());
298 localstate=stateDone;
300 localstate=stateData;
304 eDebug("local data");
308 int btw=buffersize-bytesToWrite();
311 if (data->doWrite(btw)<0)
313 localstate=stateDone;
319 done=1; // wait for remote response
323 // move to stateClose
324 if (remote_header.find("Connection") != remote_header.end())
326 eString &connection=remote_header["Connection"];
327 if (connection == "keep-alive")
328 localstate=stateWait;
330 localstate=stateClose;
334 eDebug("locate state done");
337 localstate=stateClose;
339 localstate=stateWait;
350 localstate=stateWait;
352 close(); // bye, bye, remote
362 int eHTTPConnection::processRemoteState()
366 eDebug("%d bytes avail", bytesAvailable());
368 while (((!done) || bytesAvailable()) && !abort)
376 eDebug("remote stateWait");
379 while (bytesAvailable()) {
380 i=readBlock(buffer, 1024);
388 eDebug("stateRequest");
399 del[0]=line.find(" ");
400 del[1]=line.find(" ", del[0]+1);
405 eDebug("request buggy");
406 httpversion="HTTP/1.0";
407 data=new eHTTPError(this, 400);
409 localstate=stateResponse;
410 remotestate=stateDone;
411 if (processLocalState())
415 request=line.left(del[0]);
416 requestpath=line.mid(del[0]+1, (del[1]==-1)?-1:(del[1]-del[0]-1));
420 httpversion=line.mid(del[1]+1);
424 if (is09 || (httpversion.left(7) != "HTTP/1.") || httpversion.size()!=8)
426 remotestate=stateData;
428 httpversion="HTTP/1.0";
429 content_length_remaining=content_length_remaining=0;
430 data=new eHTTPError(this, 400); // bad request - not supporting version 0.9 yet
432 remotestate=stateHeader;
438 eDebug("state response..");
448 eDebug("line: %s", line.c_str());
451 del[0]=line.find(" ");
452 del[1]=line.find(" ", del[0]+1);
457 httpversion=line.left(del[0]);
458 code=atoi(line.mid(del[0]+1, (del[1]==-1)?-1:(del[1]-del[0]-1)).c_str());
460 code_descr=line.mid(del[1]+1);
465 remotestate=stateHeader;
471 eDebug("remote stateHeader");
483 content_length_remaining=-1;
484 if (remote_header.count("Content-Length"))
486 content_length=atoi(remote_header["Content-Length"].c_str());
487 content_length_remaining=content_length;
492 for (ePtrList<eHTTPPathResolver>::iterator i(parent->resolver); i != parent->resolver.end(); ++i)
494 if ((data=i->getDataSource(request, requestpath, this)))
497 localstate=stateResponse; // can be overridden by dataSource
499 data=createDataSource(this);
505 data=new eHTTPError(this, 404);
508 if (content_length || // if content-length is set, we have content
509 remote_header.count("Content-Type") || // content-type - the same
510 (localstate != stateResponse)) // however, if we are NOT in response-state, so we are NOT server, there's ALWAYS more data to come. (exception: http/1.1 persistent)
511 remotestate=stateData;
514 data->haveData(0, 0);
515 remotestate=stateDone;
517 if (processLocalState())
521 int del=line.find(":");
522 eString name=line.left(del), value=line.mid(del+1);
525 remote_header[std::string(name)]=std::string(value);
533 eDebug("remote stateData");
538 while (bytesAvailable())
540 int tr=sizeof(buffer);
541 if (content_length_remaining != -1)
542 if (tr>content_length_remaining)
543 tr=content_length_remaining;
544 len=readBlock(buffer, tr);
545 data->haveData(buffer, len);
546 if (content_length_remaining != -1)
547 content_length_remaining-=len;
548 if (!content_length_remaining)
550 data->haveData(0, 0);
551 remotestate=stateDone;
556 if (processLocalState())
561 remotestate=stateClose;
565 remotestate=stateWait;
567 // remotestate=stateRequest;
571 eDebug("HTTP: invalid state %d", remotestate);
576 eDebug("end remote");
581 void eHTTPConnection::writeString(const char *data)
583 writeBlock(data, strlen(data));
586 int eHTTPConnection::getLine(eString &line)
592 line.erase(line.length()-1);
594 if (line[(line.length()-1)] == '\r')
595 line.erase(line.length()-1);
600 void eHTTPConnection::gotError(int err)
611 eHTTPD::eHTTPD(int port, eMainloop *ml): eServerSocket(port, ml), ml(ml)
614 eDebug("[NET] httpd server FAILED on port %d", port);
616 eDebug("[NET] httpd server started on port %d", port);
617 resolver.setAutoDelete(true);
620 eHTTPConnection::~eHTTPConnection()
622 if ((!persistent) && (state()!=Idle))
623 eWarning("~eHTTPConnection, status still %d", state());
628 void eHTTPD::newConnection(int socket)
630 new eHTTPConnection(socket, 1, this);