bool SampleService::sendm3u(BtpAction* action, DynamicObject& fileInfos) { bool rval = true; // build m3u file string content; content.append("#EXTM3U\n"); // create play list char temp[22]; FileInfoIterator i = fileInfos.getIterator(); while(i->hasNext()) { FileInfo& fi = i->next(); Media& media = fi["media"]; int sampleLength = media["sampleRange"][1]->getUInt32() - media["sampleRange"][0]->getUInt32(); snprintf(temp, 22, "%u", (sampleLength < 0 ? 0 : sampleLength)); string artist; if(media["contributors"]->hasMember("Performer")) { artist = media["contributors"]["Performer"][0]["name"]->getString(); } else if(media["contributors"]->hasMember("Artist")) { artist = media["contributors"]["Artist"][0]["name"]->getString(); } content.append("#EXTINF:"); content.append(temp); content.push_back(','); content.append(artist); content.append(" - "); content.append(media["title"]->getString()); content.push_back('\n'); // FIXME: get host from configuration or something // needs to be public IP that remote side can access DynamicObject vars; action->getResourceQuery(vars); if(!vars->hasMember("nodeuser")) { BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId()); } HttpRequestHeader* header = action->getRequest()->getHeader(); string host = header->getFieldValue("X-Forwarded-Host"); if(host.length() == 0) { host = header->getFieldValue("Host"); } content.append("http://"); content.append(host); content.append("/api/3.0/sales/samples/file/"); content.append(fi["mediaId"]->getString()); content.push_back('/'); content.append(fi["id"]->getString()); content.push_back('\n'); } // set up response header HttpResponseHeader* header = action->getResponse()->getHeader(); header->setField("Content-Type", "audio/x-mpegurl"); header->setField( "Content-Disposition", "attachment; filename=bitmunk-sample.m3u"); // create content input stream ByteBuffer b(content.length()); b.put(content.c_str(), content.length(), false); ByteArrayInputStream bais(&b); // send sample action->getResponse()->getHeader()->setStatus(200, "OK"); action->sendResult(&bais); return rval; }
void ProxyResourceHandler::operator()(BtpAction* action) { // get request host HttpRequestHeader* hrh = action->getRequest()->getHeader(); string host = hrh->getFieldValue("X-Forwarded-Host"); if(host.length() == 0) { host = hrh->getFieldValue("Host"); } // find a rule Rule* rule = findRule(action, host); if(rule == NULL) { // delegate to rest resource handler RestResourceHandler::operator()(action); } else { // get URL to proxy or redirect to UrlRef url = rule->url; // get url host string urlHost; HttpResponse* res = action->getResponse(); bool secure = res->getConnection()->isSecure(); // if URL has no host, reuse incoming host if(url->getHost().length() == 0) { urlHost = host; } // if URL has no port or uses a default port number, only use URL host else if( (url->getPort() == 0) || (secure && url->getPort() == 443) || (!secure && url->getPort() == 80)) { urlHost = url->getHost(); } // use URL host and port else { urlHost = url->getHostAndPort(); } // handle 0.0.0.0 (any host) by replacing it with the request host if(strncmp(urlHost.c_str(), "0.0.0.0", 8) == 0) { // 0.0.0.0 is 8 chars long urlHost.replace(0, 8, host.substr(0, host.find(':')).c_str()); } // rewrite the request path if it does not match URL path string path = hrh->getPath(); if(strcmp(path.c_str(), url->getPath().c_str()) != 0) { // check for path wildcard if(strcmp(rule->path, "*") == 0) { // since a wildcard is used, prepend the URL path to the // resource (if the url path isn't '/') string urlPath = url->getPath(); if(urlPath.length() > 1) { path.insert(0, url->getPath().c_str()); } } else { // replace the part of the resource that matched the proxy // rule with the rewrite path from the proxy URL path.replace(0, strlen(rule->path), url->getPath().c_str()); } } // do redirect if appropriate if(rule->type == Rule::Redirect) { // set response code HttpResponseHeader* header = res->getHeader(); if(rule->permanent) { header->setStatus(301, "Moved Permanently"); } else { header->setStatus(302, "Found"); } // build new location url bool secure = res->getConnection()->isSecure(); header->setField("Location", StringTools::format("%s://%s%s", secure ? "https" : "http", urlHost.c_str(), path.c_str())); action->sendResult(); } // do proxy else if(rule->type == Rule::Proxy) { // get client-side request HttpRequest* req = action->getRequest(); // do path rewrite hrh->setPath(path.c_str()); // add X-Forwarded headers hrh->appendFieldValue("X-Forwarded-For", req->getConnection()->getRemoteAddress()->toString(true).c_str()); hrh->appendFieldValue("X-Forwarded-Host", hrh->getFieldValue("Host").c_str()); hrh->appendFieldValue("X-Forwarded-Server", SocketTools::getHostname().c_str()); // rewrite host if rule specifies it if(rule->rewriteHost) { hrh->setField("Host", urlHost.c_str()); } // do proxy: MO_CAT_INFO(BM_NODE_CAT, "ProxyResourceHandler proxying %s%s => %s%s", host.c_str(), hrh->getPath(), urlHost.c_str(), path.c_str()); MO_CAT_DEBUG(BM_NODE_CAT, "ProxyResourceHandler request header for %s%s => %s%s:\n%s", host.c_str(), hrh->getPath(), urlHost.c_str(), path.c_str(), hrh->toString().c_str()); // get a connection BtpClient* btpc = mNode->getMessenger()->getBtpClient(); HttpConnection* conn = btpc->createConnection(false, &(*url)); if(conn == NULL) { // send service unavailable HttpResponseHeader* header = action->getResponse()->getHeader(); header->setStatus(503, "Service Unavailable"); string content = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" "<html><head>\n" "<title>503 Service Unavailable</title>\n" "</head><body>\n" "<h1>Service Unavailable</h1>\n" "<p>The service was not available.</p>\n" "</body></html>"; ByteBuffer b(content.length()); b.put(content.c_str(), content.length(), false); ByteArrayInputStream bais(&b); action->sendResult(&bais); } else { // proxy the client's request and receive server's header (by // writing it into the client's response header) HttpResponse* res = action->getResponse(); if(_proxyHttp(req->getHeader(), req->getConnection(), conn) && conn->receiveHeader(res->getHeader())) { // proxy the server's response, consider result sent _proxyHttp(res->getHeader(), conn, req->getConnection()); action->setResultSent(true); } // close connection conn->close(); // clean up delete conn; } if(!action->isResultSent()) { // send exception (client's fault if code < 500) ExceptionRef e = Exception::get(); action->sendException(e, e->getCode() < 500); } } } }