2 #include <lib/network/httpd.h>
4 #include <sys/socket.h>
5 #include <lib/base/smartptr.h>
6 #include <lib/base/estring.h>
12 #include <lib/network/http_dyn.h>
13 #include <lib/network/http_file.h>
15 eHTTPDataSource::eHTTPDataSource(eHTTPConnection *c): connection(c)
19 eHTTPDataSource::~eHTTPDataSource()
23 void eHTTPDataSource::haveData(void *data, int len)
27 int eHTTPDataSource::doWrite(int)
32 DEFINE_REF(eHTTPError);
34 eHTTPError::eHTTPError(eHTTPConnection *c, int errcode): eHTTPDataSource(c), errcode(errcode)
36 std::string error="unknown error";
39 case 400: error="Bad Request"; break;
40 case 401: error="Unauthorized"; break;
41 case 403: error="Forbidden"; break;
42 case 404: error="Not found"; break;
43 case 405: error="Method not allowed"; break;
44 case 500: error="Internal server error"; break;
46 connection->code_descr=error;
47 connection->code=errcode;
49 connection->local_header["Content-Type"]=std::string("text/html");
52 int eHTTPError::doWrite(int w)
55 html+="<html><head><title>Error " + getNum(connection->code) + "</title></head>"+
56 "<body><h1>Error " + getNum(errcode) + ": " + connection->code_descr + "</h1></body></html>\n";
57 connection->writeBlock(html.c_str(), html.length());
61 eHTTPConnection::eHTTPConnection(int socket, int issocket, eHTTPD *parent, int persistent): eSocket(socket, issocket, parent->ml), parent(parent), persistent(persistent)
64 eDebug("eHTTPConnection");
66 CONNECT(this->readyRead_ , eHTTPConnection::readData);
67 CONNECT(this->bytesWritten_ , eHTTPConnection::bytesWritten);
68 CONNECT(this->error_ , eHTTPConnection::gotError);
69 CONNECT(this->connectionClosed_ , eHTTPConnection::destruct);
70 CONNECT(this->hangup , eHTTPConnection::gotHangup);
74 remotestate=stateRequest;
78 void eHTTPConnection::destruct()
80 eDebug("destruct, this %p!", this);
85 eHTTPConnection::eHTTPConnection(eMainloop *ml): eSocket(ml), parent(0), persistent(0)
87 CONNECT(this->readyRead_ , eHTTPConnection::readData);
88 CONNECT(this->bytesWritten_ , eHTTPConnection::bytesWritten);
89 CONNECT(this->error_ , eHTTPConnection::gotError);
90 CONNECT(this->connected_ , eHTTPConnection::hostConnected);
91 CONNECT(this->connectionClosed_ , eHTTPConnection::destruct);
94 remotestate=stateWait;
100 void eHTTPConnection::hostConnected()
105 void eHTTPConnection::start()
107 if (localstate==stateWait)
109 localstate=stateRequest;
114 void eHTTPConnection::gotHangup()
116 if (data && remotestate == stateData)
117 data->haveData(0, 0);
121 localstate=stateWait;
122 remotestate=stateRequest;
124 remote_header.clear();
125 local_header.clear();
128 eHTTPConnection *eHTTPConnection::doRequest(const char *uri, eMainloop *ml, int *error)
133 char *defaultproto="http";
134 std::string proto, host, path;
137 int state=0; // 0 proto, 1 host, 2 port 3 path
144 if (!strncmp(uri, "://", 3))
148 } else if ((*uri=='/') || (*uri==':'))
154 proto.push_back(*uri++);
165 host.push_back(*uri++);
184 path.push_back(*uri++);
195 eDebug("proto: '%s', host '%s', path '%s', port '%d'", proto.c_str(), host.c_str(), path.c_str(), port);
200 eDebug("no host given");
206 if (strcmp(proto.c_str(), "http"))
208 eDebug("invalid protocol (%s)", proto.c_str());
216 eDebug("invalid port");
225 eHTTPConnection *c=new eHTTPConnection(ml);
227 c->requestpath=path.c_str();
228 c->httpversion="HTTP/1.0";
229 c->local_header["Host"]=host;
230 if ((*error=c->connectToHost(host, port))) // already deleted by error
235 void eHTTPConnection::readData()
237 processRemoteState();
240 void eHTTPConnection::bytesWritten(int)
245 int eHTTPConnection::processLocalState()
258 eDebug("processing local state %d", localstate);
264 eDebug("local wait");
271 eDebug("local request");
273 std::string req=request+" "+requestpath+" "+httpversion+"\r\n";
274 writeBlock(req.c_str(), req.length());
275 localstate=stateHeader;
276 remotestate=stateResponse;
282 eDebug("local Response");
284 writeString( (httpversion + " " + getNum(code) + " " + code_descr + "\r\n").c_str() );
285 localstate=stateHeader;
286 local_header["Connection"]="close";
291 eDebug("local header");
293 for (std::map<std::string,std::string>::iterator cur=local_header.begin(); cur!=local_header.end(); ++cur)
295 writeString(cur->first.c_str());
297 writeString(cur->second.c_str());
302 localstate=stateDone;
304 localstate=stateData;
308 eDebug("local data");
312 int btw=buffersize-bytesToWrite();
315 if (data->doWrite(btw)<0)
317 localstate=stateDone;
323 done=1; // wait for remote response
327 // move to stateClose
328 if (remote_header.find("Connection") != remote_header.end())
330 std::string &connection=remote_header["Connection"];
331 if (connection == "keep-alive")
332 localstate=stateWait;
334 localstate=stateClose;
338 eDebug("locate state done");
341 localstate=stateClose;
343 localstate=stateWait;
352 localstate = stateWait;
354 close(); // bye, bye, remote
364 int eHTTPConnection::processRemoteState()
368 eDebug("%d bytes avail", bytesAvailable());
370 while (((!done) || bytesAvailable()) && !abort)
378 eDebug("remote stateWait");
381 while (bytesAvailable()) {
382 i=readBlock(buffer, 1024);
390 eDebug("stateRequest");
401 del[0]=line.find(" ");
402 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 (eSmartPtrList<iHTTPPathResolver>::iterator i(parent->resolver); i != parent->resolver.end(); ++i)
494 if (!(i->getDataSource(data, request, requestpath, this)))
496 localstate=stateResponse; // can be overridden by dataSource
498 data=createDataSource(this);
503 data = new eHTTPError(this, 404);
506 if (content_length || // if content-length is set, we have content
507 remote_header.count("Content-Type") || // content-type - the same
508 (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)
509 remotestate=stateData;
512 data->haveData(0, 0);
513 remotestate=stateDone;
515 if (processLocalState())
519 int del=line.find(":");
520 std::string name=line.substr(0, del), value=line.substr(del+1);
522 value=value.substr(1);
523 remote_header[std::string(name)]=std::string(value);
531 eDebug("remote stateData");
536 while (bytesAvailable())
538 int tr=sizeof(buffer);
539 if (content_length_remaining != -1)
540 if (tr>content_length_remaining)
541 tr=content_length_remaining;
542 len=readBlock(buffer, tr);
543 data->haveData(buffer, len);
544 if (content_length_remaining != -1)
545 content_length_remaining-=len;
546 if (!content_length_remaining)
548 data->haveData(0, 0);
549 remotestate=stateDone;
554 if (processLocalState())
559 remotestate=stateClose;
563 remotestate=stateWait;
565 // remotestate=stateRequest;
569 eDebug("HTTP: invalid state %d", remotestate);
574 eDebug("end remote");
579 void eHTTPConnection::writeString(const char *data)
581 writeBlock(data, strlen(data));
584 int eHTTPConnection::getLine(std::string &line)
590 line.erase(line.length()-1);
592 if (line[(line.length()-1)] == '\r')
593 line.erase(line.length()-1);
598 void eHTTPConnection::gotError(int err)
605 eHTTPD::eHTTPD(int port, eMainloop *ml): eServerSocket(port, ml), ml(ml)
608 eDebug("[NET] httpd server FAILED on port %d", port);
610 eDebug("[NET] httpd server started on port %d", port);
613 eHTTPConnection::~eHTTPConnection()
615 eDebug("HTTP connection destruct");
616 if ((!persistent) && (state()!=Idle))
617 eWarning("~eHTTPConnection, status still %d", state());
620 void eHTTPD::newConnection(int socket)
622 new eHTTPConnection(socket, 1, this);