diff options
| author | kwacker <vdr@w-i-r.com> | 2010-04-11 13:46:11 +0200 |
|---|---|---|
| committer | kwacker <vdr@w-i-r.com> | 2010-04-11 13:46:11 +0200 |
| commit | 9b144d30e0ea8ce900c37b96ba2cbdda14b0ae88 (patch) | |
| tree | 3a52de029f950dcd9f9856a53fd67abef8519e68 /plugins/streamdev/streamdev-cvs/server/connectionHTTP.c | |
| parent | 9cd931834ecadbf5efefdf484abb966e9248ebbb (diff) | |
| download | x-vdr-9b144d30e0ea8ce900c37b96ba2cbdda14b0ae88.tar.gz x-vdr-9b144d30e0ea8ce900c37b96ba2cbdda14b0ae88.tar.bz2 | |
Burn 0.2.0-beta3 und Streamdev mit Paches aktualisiert
Diffstat (limited to 'plugins/streamdev/streamdev-cvs/server/connectionHTTP.c')
| -rw-r--r-- | plugins/streamdev/streamdev-cvs/server/connectionHTTP.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionHTTP.c b/plugins/streamdev/streamdev-cvs/server/connectionHTTP.c new file mode 100644 index 0000000..83e568d --- /dev/null +++ b/plugins/streamdev/streamdev-cvs/server/connectionHTTP.c @@ -0,0 +1,296 @@ +/* + * $Id: connectionHTTP.c,v 1.17 2009/06/19 06:32:45 schmirl Exp $ + */ + +#include <ctype.h> + +#include "server/connectionHTTP.h" +#include "server/menuHTTP.h" +#include "server/server.h" +#include "server/setup.h" + +cConnectionHTTP::cConnectionHTTP(void): + cServerConnection("HTTP"), + m_Status(hsRequest), + m_LiveStreamer(NULL), + m_StreamerParameter(""), + m_Channel(NULL), + m_Apid(0), + m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType), + m_ChannelList(NULL) +{ + Dprintf("constructor hsRequest\n"); +} + +cConnectionHTTP::~cConnectionHTTP() +{ + delete m_LiveStreamer; +} + +bool cConnectionHTTP::CanAuthenticate(void) +{ + return opt_auth != NULL; +} + +bool cConnectionHTTP::Command(char *Cmd) +{ + Dprintf("command %s\n", Cmd); + switch (m_Status) { + case hsRequest: + Dprintf("Request\n"); + m_Request = Cmd; + m_Status = hsHeaders; + return true; + + case hsHeaders: + if (*Cmd == '\0') { + m_Status = hsBody; + return ProcessRequest(); + } + if (strncasecmp(Cmd, "Host:", 5) == 0) { + Dprintf("Host-Header\n"); + m_Host = (std::string) skipspace(Cmd + 5); + return true; + } + else if (strncasecmp(Cmd, "Authorization:", 14) == 0) { + Cmd = skipspace(Cmd + 14); + if (strncasecmp(Cmd, "Basic", 5) == 0) { + Dprintf("'Authorization Basic'-Header\n"); + m_Authorization = (std::string) skipspace(Cmd + 5); + return true; + } + } + Dprintf("header\n"); + return true; + default: + // skip additional blank lines + if (*Cmd == '\0') + return true; + break; + } + return false; // ??? shouldn't happen +} + +bool cConnectionHTTP::ProcessRequest(void) +{ + Dprintf("process\n"); + if (!StreamdevHosts.Acceptable(RemoteIpAddr())) + { + if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) { + isyslog("streamdev-server: HTTP authorization required"); + DeferClose(); + return Respond("HTTP/1.0 401 Authorization Required") + && Respond("WWW-authenticate: basic Realm=\"Streamdev-Server\")") + && Respond(""); + } + } + if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) { + switch (m_Job) { + case hjListing: + if (m_ChannelList) + return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); + break; + + case hjTransfer: + if (m_Channel == NULL) { + DeferClose(); + return Respond("HTTP/1.0 404 not found"); + } + + m_LiveStreamer = new cStreamdevLiveStreamer(0, m_StreamerParameter); + cDevice *device = GetDevice(m_Channel, 0); + if (device != NULL) { + device->SwitchChannel(m_Channel, false); + if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) { + m_LiveStreamer->SetDevice(device); + if (!SetDSCP()) + LOG_ERROR_STR("unable to set DSCP sockopt"); + if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) { + return Respond("HTTP/1.0 200 OK") + && Respond("Content-Type: audio/mpeg") + && Respond("icy-name: %s", true, m_Channel->Name()) + && Respond(""); + } else { + return Respond("HTTP/1.0 200 OK") + && Respond("Content-Type: video/mpeg") + && Respond(""); + } + } + } + DELETENULL(m_LiveStreamer); + DeferClose(); + return Respond("HTTP/1.0 409 Channel not available") + && Respond(""); + } + } + + DeferClose(); + return Respond("HTTP/1.0 400 Bad Request") + && Respond(""); +} + +void cConnectionHTTP::Flushed(void) +{ + std::string line; + + if (m_Status != hsBody) + return; + + switch (m_Job) { + case hjListing: + if (m_ChannelList) { + if (m_ChannelList->HasNext()) { + if (!Respond("%s", true, m_ChannelList->Next().c_str())) + DeferClose(); + } + else { + DELETENULL(m_ChannelList); + m_Status = hsFinished; + DeferClose(); + } + return; + } + // should never be reached + esyslog("streamdev-server cConnectionHTTP::Flushed(): no channel list"); + m_Status = hsFinished; + break; + + case hjTransfer: + Dprintf("streamer start\n"); + m_LiveStreamer->Start(this); + m_Status = hsFinished; + break; + } +} + +bool cConnectionHTTP::CmdGET(const std::string &Opts) +{ + const char *ptr, *sp, *pp, *fp, *xp, *qp, *ep; + const cChannel *chan; + int apid = 0; + + ptr = Opts.c_str(); + + // find begin of URL + sp = skipspace(ptr); + // find end of URL (\0 or first space character) + for (ep = sp; *ep && !isspace(*ep); ep++) + ; + // find begin of query string (first ?) + for (qp = sp; qp < ep && *qp != '?'; qp++) + ; + // find begin of filename (last /) + for (fp = qp; fp > sp && *fp != '/'; --fp) + ; + // find begin of section params (first ;) + for (pp = sp; pp < fp && *pp != ';'; pp++) + ; + // find filename extension (first .) + for (xp = fp; xp < qp && *xp != '.'; xp++) + ; + if (qp - xp > 5) // too long for a filename extension + xp = qp; + + std::string type, filespec, fileext, query; + // Streamtype with leading / stripped off + if (pp > sp) + type = Opts.substr(sp - ptr + 1, pp - sp - 1); + // Section parameters with leading ; stripped off + if (fp > pp) + m_StreamerParameter = Opts.substr(pp - ptr + 1, fp - pp - 1); + // file basename with leading / stripped off + if (xp > fp) + filespec = Opts.substr(fp - ptr + 1, xp - fp - 1); + // file extension including leading . + fileext = Opts.substr(xp - ptr, qp - xp); + // query string including leading ? + query = Opts.substr(qp - ptr, ep - qp); + + Dprintf("before channelfromstring: type(%s) param(%s) filespec(%s) fileext(%s) query(%s)\n", type.c_str(), m_StreamerParameter.c_str(), filespec.c_str(), fileext.c_str(), query.c_str()); + + const char* pType = type.c_str(); + if (strcasecmp(pType, "PS") == 0) { + m_StreamType = stPS; + } else if (strcasecmp(pType, "PES") == 0) { + m_StreamType = stPES; + } else if (strcasecmp(pType, "TS") == 0) { + m_StreamType = stTS; + } else if (strcasecmp(pType, "ES") == 0) { + m_StreamType = stES; + } else if (strcasecmp(pType, "Extern") == 0) { + m_StreamType = stExtern; + } + + std::string groupTarget; + cChannelIterator *iterator = NULL; + + if (filespec.compare("tree") == 0) { + const cChannel* c = NULL; + size_t groupIndex = query.find("group="); + if (groupIndex != std::string::npos) + c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); + iterator = new cListTree(c); + groupTarget = filespec + fileext; + } else if (filespec.compare("groups") == 0) { + iterator = new cListGroups(); + groupTarget = (std::string) "group" + fileext; + } else if (filespec.compare("group") == 0) { + const cChannel* c = NULL; + size_t groupIndex = query.find("group="); + if (groupIndex != std::string::npos) + c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); + iterator = new cListGroup(c); + } else if (filespec.compare("channels") == 0) { + iterator = new cListChannels(); + } else if (filespec.compare("all") == 0 || + (filespec.empty() && fileext.empty())) { + iterator = new cListAll(); + } + + if (iterator) { + if (filespec.empty() || fileext.compare(".htm") == 0 || fileext.compare(".html") == 0) { + m_ChannelList = new cHtmlChannelList(iterator, m_StreamType, (filespec + fileext + query).c_str(), groupTarget.c_str()); + m_Job = hjListing; + } else if (fileext.compare(".m3u") == 0) { + std::string base; + if (*(m_Host.c_str())) + base = "http://" + m_Host + "/"; + else + base = (std::string) "http://" + LocalIp() + ":" + + (const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/"; + if (type.empty()) + { + switch (m_StreamType) + { + case stTS: base += "TS/"; break; + case stPS: base += "PS/"; break; + case stPES: base += "PES/"; break; + case stES: base += "ES/"; break; + case stExtern: base += "Extern/"; break; + default: break; + + } + } else { + base += type; + if (!m_StreamerParameter.empty()) + base += ";" + m_StreamerParameter; + base += "/"; + } + m_ChannelList = new cM3uChannelList(iterator, base.c_str()); + m_Job = hjListing; + } else { + delete iterator; + return false; + } + } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) { + m_Channel = chan; + m_Apid = apid; + Dprintf("Apid is %d\n", apid); + m_Job = hjTransfer; + } else + return false; + + Dprintf("after channelfromstring\n"); + return true; +} + |
