Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- The intent of this code snippet is to stream an attachment from CouchDB via Lasso as a proxy.
- CouchDB can serve the content directly, but this prevents Lasso from being able to handle logging and authentication.
- I want Lasso to act as a proxy so that I can perform arbitrary tasks (logging, auth) before serving the file,
- without having to sacrifice the streaming behaviour the CouchDB provides.
- #COUCHDB_URL could be any media file of any size.
- I've tested it successfully with a small Word document, a 10MB PDF, and a 20MB WMV
- However, so far both a 50MB FLV and 60MB MP4 file have both failed.
- */
- // initialize a curl object with the URL to the media file served from CouchDB
- local(req) = curl( #COUCHDB_URL );
- // set outgoing headers to match the headers served from CouchDB
- // first, perform a HEAD request to fetch the headers
- local(result) = #req->set(CURLOPT_NOBODY, 1);
- // parse headers (skip first 4 lines, which are response status, server, etag and date)
- // this leaves Content-Type, Content-MD5, Content-Length, Cache-Control, Accept-Ranges
- #result = #req->header->trim&->split("\r\n");
- local(couchheaders) = ( with h in #result skip 4 where #h->size > 0 let vals = #h->split(": ") select pair(#vals->first->asstring = #vals->second->asstring) )->asstaticarray->asarray;
- // combine CouchDB headers with Lasso's default headers
- #result = web_response->setHeaders( #couchheaders );
- // headers are now set, we can begin streaming data now
- // the code below comes from a combination of the example at:
- // http://www.lassosoft.com/lassoDocs/languageReference/obj/curl_multi_perform
- // and Jolle's CSV streaming technique, from:
- // https://gist.github.com/jolle-c/bec94c372d8bd74c5477
- local(ctoken, err, data, headerBytes = bytes, bodyBytes = bytes, ready = false)
- #ctoken = curl_easy_init
- #err = curl_easy_setopt(#ctoken, curlopt_url, #COUCHDB_URL );
- while(!#ready) => {
- #data = curl_multi_perform(#ctoken)
- // #data->first is a boolean representing whether transfer is ongoing
- // #data->second is the header data, which we're ignoring
- // #data->last is the body data
- if( #data->last->isa(::bytes) );
- #bodyBytes->append(#data->last)
- /if;
- // when #bodyBytes becomes larger than the fcgi_bodyChunkSize, send a chunk
- if(#bodyBytes->size > fcgi_bodyChunkSize) => {
- web_response->rawcontent = #bodyBytes
- web_response->sendChunk
- #bodyBytes = bytes
- }
- #ready = !#data->first
- }
- // if there's anything left in the #bodyBytes buffer, serve it, then abort.
- web_response->rawcontent = #bodyBytes; abort;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement