Advertisement
Guest User

Untitled

a guest
May 28th, 2016
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.55 KB | None | 0 0
  1. /*
  2. The intent of this code snippet is to stream an attachment from CouchDB via Lasso as a proxy.
  3. CouchDB can serve the content directly, but this prevents Lasso from being able to handle logging and authentication.
  4. I want Lasso to act as a proxy so that I can perform arbitrary tasks (logging, auth) before serving the file,
  5. without having to sacrifice the streaming behaviour the CouchDB provides.
  6. #COUCHDB_URL could be any media file of any size.
  7. I've tested it successfully with a small Word document, a 10MB PDF, and a 20MB WMV
  8. However, so far both a 50MB FLV and 60MB MP4 file have both failed.
  9. */
  10.  
  11. // initialize a curl object with the URL to the media file served from CouchDB
  12. local(req) = curl( #COUCHDB_URL );
  13.  
  14. // set outgoing headers to match the headers served from CouchDB
  15.  
  16. // first, perform a HEAD request to fetch the headers
  17. local(result) = #req->set(CURLOPT_NOBODY, 1);
  18.  
  19. // parse headers (skip first 4 lines, which are response status, server, etag and date)
  20. // this leaves Content-Type, Content-MD5, Content-Length, Cache-Control, Accept-Ranges
  21.  
  22. #result = #req->header->trim&->split("\r\n");
  23. 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;
  24.  
  25. // combine CouchDB headers with Lasso's default headers
  26. #result = web_response->setHeaders( #couchheaders );
  27.  
  28. // headers are now set, we can begin streaming data now
  29.  
  30. // the code below comes from a combination of the example at:
  31. // http://www.lassosoft.com/lassoDocs/languageReference/obj/curl_multi_perform
  32. // and Jolle's CSV streaming technique, from:
  33. // https://gist.github.com/jolle-c/bec94c372d8bd74c5477
  34.  
  35. local(ctoken, err, data, headerBytes = bytes, bodyBytes = bytes, ready = false)
  36.  
  37. #ctoken = curl_easy_init
  38. #err = curl_easy_setopt(#ctoken, curlopt_url, #COUCHDB_URL );
  39.  
  40. while(!#ready) => {
  41. #data = curl_multi_perform(#ctoken)
  42. // #data->first is a boolean representing whether transfer is ongoing
  43. // #data->second is the header data, which we're ignoring
  44. // #data->last is the body data
  45.  
  46. if( #data->last->isa(::bytes) );
  47. #bodyBytes->append(#data->last)
  48. /if;
  49.  
  50. // when #bodyBytes becomes larger than the fcgi_bodyChunkSize, send a chunk
  51. if(#bodyBytes->size > fcgi_bodyChunkSize) => {
  52. web_response->rawcontent = #bodyBytes
  53. web_response->sendChunk
  54. #bodyBytes = bytes
  55. }
  56. #ready = !#data->first
  57. }
  58. // if there's anything left in the #bodyBytes buffer, serve it, then abort.
  59. web_response->rawcontent = #bodyBytes; abort;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement