2 #include <lib/network/httpd.h>
4 #include <sys/socket.h>
5 #include <lib/base/estring.h>
11 eHTTPDataSource::eHTTPDataSource(eHTTPConnection *c): connection(c)
15 eHTTPDataSource::~eHTTPDataSource()
19 void eHTTPDataSource::haveData(void *data, int len)
23 int eHTTPDataSource::doWrite(int)
28 eHTTPError::eHTTPError(eHTTPConnection *c, int errcode): eHTTPDataSource(c), errcode(errcode)
30 std::string error="unknown error";
33 case 400: error="Bad Request"; break;
34 case 401: error="Unauthorized"; break;
35 case 403: error="Forbidden"; break;
36 case 404: error="Not found"; break;
37 case 405: error="Method not allowed"; break;
38 case 500: error="Internal server error"; break;
40 connection->code_descr=error;
41 connection->code=errcode;
43 connection->local_header["Content-Type"]=std::string("text/html");
46 int eHTTPError::doWrite(int w)
49 html+="<html><head><title>Error " + getNum(connection->code) + "</title></head>"+
50 "<body><h1>Error " + getNum(errcode) + ": " + connection->code_descr + "</h1></body></html>\n";
51 connection->writeBlock(html.c_str(), html.length());
55 eHTTPConnection::eHTTPConnection(int socket, int issocket, eHTTPD *parent, int persistent): eSocket(socket, issocket, parent->ml), parent(parent), persistent(persistent)
58 eDebug("eHTTPConnection");
60 CONNECT(this->readyRead_ , eHTTPConnection::readData);
61 CONNECT(this->bytesWritten_ , eHTTPConnection::bytesWritten);
62 CONNECT(this->error_ , eHTTPConnection::gotError);
63 CONNECT(this->connectionClosed_ , eHTTPConnection::destruct);
64 CONNECT(this->hangup , eHTTPConnection::gotHangup);
68 remotestate=stateRequest;
72 void eHTTPConnection::destruct()
78 eHTTPConnection::eHTTPConnection(eMainloop *ml): eSocket(ml), parent(0), persistent(0)
80 CONNECT(this->readyRead_ , eHTTPConnection::readData);
81 CONNECT(this->bytesWritten_ , eHTTPConnection::bytesWritten);
82 CONNECT(this->error_ , eHTTPConnection::gotError);
83 CONNECT(this->connected_ , eHTTPConnection::hostConnected);
84 CONNECT(this->connectionClosed_ , eHTTPConnection::destruct);
87 remotestate=stateWait;
93 void eHTTPConnection::hostConnected()
98 void eHTTPConnection::start()
100 if (localstate==stateWait)
102 localstate=stateRequest;
107 void eHTTPConnection::gotHangup()
109 if (data && remotestate == stateData)
110 data->haveData(0, 0);
118 localstate=stateWait;
119 remotestate=stateRequest;
121 remote_header.clear();
122 local_header.clear();
125 eHTTPConnection *eHTTPConnection::doRequest(const char *uri, eMainloop *ml, int *error)
130 char *defaultproto="http";
131 std::string proto, host, path;
134 int state=0; // 0 proto, 1 host, 2 port 3 path
141 if (!strncmp(uri, "://", 3))
145 } else if ((*uri=='/') || (*uri==':'))
151 proto.push_back(*uri++);
162 host.push_back(*uri++);
181 path.push_back(*uri++);
192 eDebug("proto: '%s', host '%s', path '%s', port '%d'", proto.c_str(), host.c_str(), path.c_str(), port);
197 eDebug("no host given");
203 if (strcmp(proto.c_str(), "http"))
205 eDebug("invalid protocol (%s)", proto.c_str());
213 eDebug("invalid port");
222 eHTTPConnection *c=new eHTTPConnection(ml);
224 c->requestpath=path.c_str();
225 c->httpversion="HTTP/1.0";
226 c->local_header["Host"]=host;
227 if ((*error=c->connectToHost(host, port))) // already deleted by error
232 void eHTTPConnection::readData()
234 processRemoteState();
237 void eHTTPConnection::bytesWritten(int)
242 int eHTTPConnection::processLocalState()
255 eDebug("processing local state %d", localstate);
261 eDebug("local wait");
268 eDebug("local request");
270 std::string req=request+" "+requestpath+" "+httpversion+"\r\n";
271 writeBlock(req.c_str(), req.length());
272 localstate=stateHeader;
273 remotestate=stateResponse;
279 eDebug("local Response");
281 writeString( (httpversion + " " + getNum(code) + " " + code_descr + "\r\n").c_str() );
282 localstate=stateHeader;
283 local_header["Connection"]="close";
288 eDebug("local header");
290 for (std::map<std::string,std::string>::iterator cur=local_header.begin(); cur!=local_header.end(); ++cur)
292 writeString(cur->first.c_str());
294 writeString(cur->second.c_str());
299 localstate=stateDone;
301 localstate=stateData;
305 eDebug("local data");
309 int btw=buffersize-bytesToWrite();
312 if (data->doWrite(btw)<0)
314 localstate=stateDone;
320 done=1; // wait for remote response
324 // move to stateClose
325 if (remote_header.find("Connection") != remote_header.end())
327 std::string &connection=remote_header["Connection"];
328 if (connection == "keep-alive")
329 localstate=stateWait;
331 localstate=stateClose;
335 eDebug("locate state done");
338 localstate=stateClose;
340 localstate=stateWait;
351 localstate=stateWait;
353 close(); // bye, bye, remote
363 int eHTTPConnection::processRemoteState()
367 eDebug("%d bytes avail", bytesAvailable());
369 while (((!done) || bytesAvailable()) && !abort)
377 eDebug("remote stateWait");
380 while (bytesAvailable()) {
381 i=readBlock(buffer, 1024);
389 eDebug("stateRequest");
400 del[0]=line.find(" ");
401 del[1]=line.find(" ", del[0]+1);
406 eDebug("request buggy");
407 httpversion="HTTP/1.0";
408 data=new eHTTPError(this, 400);
410 localstate=stateResponse;
411 remotestate=stateDone;
412 if (processLocalState())
416 request=line.substr(0, del[0]);
417 requestpath=line.substr(del[0]+1, (del[1]==-1)?-1:(del[1]-del[0]-1));
421 httpversion=line.substr(del[1]+1);
425 if (is09 || (httpversion.substr(0, 7) != "HTTP/1.") || httpversion.size()!=8)
427 remotestate=stateData;
429 httpversion="HTTP/1.0";
430 content_length_remaining=content_length_remaining=0;
431 data=new eHTTPError(this, 400); // bad request - not supporting version 0.9 yet
433 remotestate=stateHeader;
439 eDebug("state response..");
449 eDebug("line: %s", line.c_str());
452 del[0]=line.find(" ");
453 del[1]=line.find(" ", del[0]+1);
458 httpversion=line.substr(0, del[0]);
459 code=atoi(line.substr(del[0]+1, (del[1]==-1)?-1:(del[1]-del[0]-1)).c_str());
461 code_descr=line.substr(del[1]+1);
466 remotestate=stateHeader;
472 eDebug("remote stateHeader");
484 content_length_remaining=-1;
485 if (remote_header.count("Content-Length"))
487 content_length=atoi(remote_header["Content-Length"].c_str());
488 content_length_remaining=content_length;
493 for (ePtrList<eHTTPPathResolver>::iterator i(parent->resolver); i != parent->resolver.end(); ++i)
495 if ((data=i->getDataSource(request, requestpath, this)))
498 localstate=stateResponse; // can be overridden by dataSource
500 data=createDataSource(this);
506 data=new eHTTPError(this, 404);
509 if (content_length || // if content-length is set, we have content
510 remote_header.count("Content-Type") || // content-type - the same
511 (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)
512 remotestate=stateData;
515 data->haveData(0, 0);
516 remotestate=stateDone;
518 if (processLocalState())
522 int del=line.find(":");
523 std::string name=line.substr(0, del), value=line.substr(del+1);
525 value=value.substr(1);
526 remote_header[std::string(name)]=std::string(value);
534 eDebug("remote stateData");
539 while (bytesAvailable())
541 int tr=sizeof(buffer);
542 if (content_length_remaining != -1)
543 if (tr>content_length_remaining)
544 tr=content_length_remaining;
545 len=readBlock(buffer, tr);
546 data->haveData(buffer, len);
547 if (content_length_remaining != -1)
548 content_length_remaining-=len;
549 if (!content_length_remaining)
551 data->haveData(0, 0);
552 remotestate=stateDone;
557 if (processLocalState())
562 remotestate=stateClose;
566 remotestate=stateWait;
568 // remotestate=stateRequest;
572 eDebug("HTTP: invalid state %d", remotestate);
577 eDebug("end remote");
582 void eHTTPConnection::writeString(const char *data)
584 writeBlock(data, strlen(data));
587 int eHTTPConnection::getLine(std::string &line)
593 line.erase(line.length()-1);
595 if (line[(line.length()-1)] == '\r')
596 line.erase(line.length()-1);
601 void eHTTPConnection::gotError(int err)
612 eHTTPD::eHTTPD(int port, eMainloop *ml): eServerSocket(port, ml), ml(ml)
615 eDebug("[NET] httpd server FAILED on port %d", port);
617 eDebug("[NET] httpd server started on port %d", port);
618 #warning resolver autodelete removed
621 eHTTPConnection::~eHTTPConnection()
623 if ((!persistent) && (state()!=Idle))
624 eWarning("~eHTTPConnection, status still %d", state());
629 void eHTTPD::newConnection(int socket)
631 new eHTTPConnection(socket, 1, this);