Branch: Tag:

2016-04-22

2016-04-22 11:41:33 by Pontus Östlund <ponost@roxen.com>

Web.Api.Api: Fixed so that POST actions actually works.

It now also tries to detect if a file is being uploaded. This works by looking at the parameter values and if a value contains "filename=..." a multipart message will be created. So in short this would look something like:

string file = "the-file.png";
string data = Stdio.read_file(file);
mapping params = ([ "the_file_param" : "filename=" + file ]);

api->post("method/endpoint", params, data);

9:   //! Look at the code in @[Web.Api.Github], @[Web.Api.Instagram],   //! @[Web.Api.Linkedin] etc to see some examples of implementations.    - // #define SOCIAL_REQUEST_DEBUG -  +    #if defined(SOCIAL_REQUEST_DEBUG) || defined(SOCIAL_REQUEST_DATA_DEBUG)   # define TRACE(X...) werror("%s:%d: %s",basename(__FILE__),__LINE__,sprintf(X))   #else
251:    }    }    -  if (http_method == "POST") { -  if (!data) data = (string) p; +  mapping request_headers = copy_value(default_headers); +  params = (mapping) p; +  +  if ((< "POST" >)[http_method]) { +  if (!data) { +  data = (string) p;    params = 0;    }    else { -  +  array(string) parts = make_multipart_message(params, data); +  request_headers["content-type"] = parts[0]; +  data = parts[1]; +  params = 0; +  } +  } +  else {    params = (mapping) p;    }   
267: Inside #if defined(SOCIAL_REQUEST_DEBUG)
     #ifdef SOCIAL_REQUEST_DEBUG    TRACE("\n> Request: %s %s?%s\n", http_method, api_method, (string) p); -  if (data) TRACE("> data: %s\n", data); +  if (data) { +  if (sizeof(data) > 100) { +  TRACE("> data: %s\n", data[0..100]); +  } +  else { +  TRACE("> data: %s\n", data); +  } +  }   #endif       if (cb) {
295:    );       Protocols.HTTP.do_async_method(http_method, api_method, params, -  default_headers, req, data); +  request_headers, req, data);       return 0;    }       req = Protocols.HTTP.do_method(http_method, api_method, params, -  default_headers, req, data); +  request_headers, req, data); +     return req && handle_response(req);   }    -  + //! Creates the body of an Upload request + //! + //! @param p + //! The API request parameters + //! + //! @param body + //! Data of the document to upload + //! + //! @returns + //! An array with two indices: + //! @ul + //! @item + //! The value for the main Content-Type header + //! @item + //! The request body + //! @endul + protected array(string) make_multipart_message(mapping p, string body) + { +  string boundary = "----PikeWebApi" + +  (string)Standards.UUID.make_version4(); +  +  mapping subh = ([ "Content-Disposition" : "form-data" ]); +  array(MIME.Message) msgs = ({}); +  +  foreach (p; string k; string v) { +  MIME.Message m; +  mapping h = copy_value(subh); +  +  if (search(v, "filename=") > -1) { +  string name; +  +  if (sscanf(v, "%*sfilename=\"%s\"", name) != 2) { +  if (sscanf(v, "%*sfilename=%s", name) != 2) { +  error("Unable to resolve filename! Please fix the value " +  "for the parameter %O\n!", k); +  } +  } +  +  string type = Protocols.HTTP.Server.filename_to_type(name); +  h["Content-Type"] = type; +  m = MIME.Message(body, h); +  m->setdisp_param("filename", name); +  m->setdisp_param("name", k); +  } +  else { +  m = MIME.Message(v, h); +  m->setdisp_param("name", k); +  } +  msgs += ({ m }); +  } +  +  mapping mainh = ([ "Content-Type" : "multipart/form-data" ]); +  MIME.Message main = MIME.Message("", mainh, msgs); +  main->setboundary(boundary); +  +  string raw = (string) main; +  sscanf(raw, "%s\r\n\r\n%s", string header, string cont); +  sscanf(header, "%*sContent-Type: %s", string hval); +  +  return ({ hval, cont }); + } +  +    //! Forcefully close all HTTP connections. This only has effect in   //! async mode.   void close_connections()
316:    foreach (values(_query_objects), array m) {    catch {    Protocols.HTTP.Query q = m[0]; +     if (q && q->con && q->con->is_open()) { - #ifdef SOCIAL_REQUEST_DEBUG -  werror("%s:%d: Forecefully closing open connection: %O\n", -  basename(__FILE__),__LINE__,q); - #endif +  TRACE("Forecefully closing open connection: %O\n", q); +     q->close();       if (m[1]) {
334:    _query_objects = ([]);   }    - private mixed handle_response(Protocols.HTTP.Query req) + protected mixed handle_response(Protocols.HTTP.Query req)   {    TRACE("Handle response: %O\n", req);