HTTP-Parser-XS

 view release on metacpan or  search on metacpan

XS.xs  view on Meta::CPAN

  if (question_at != path_len)
    ++question_at;
  hv_store(env, "QUERY_STRING", sizeof("QUERY_STRING") - 1,
	   newSVpvn(path + question_at, path_len - question_at), 0);
  sprintf(tmp, "HTTP/1.%d", minor_version);
  hv_store(env, "SERVER_PROTOCOL", sizeof("SERVER_PROTOCOL") - 1,
           newSVpv(tmp, 0), 0);
  last_value = NULL;
  for (i = 0; i < num_headers; ++i) {
    if (headers[i].name != NULL) {
      const char* name;
      size_t name_len;
      SV** slot;
      if (header_is(headers + i, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1)) {
	name = "CONTENT_TYPE";
	name_len = sizeof("CONTENT_TYPE") - 1;
      } else if (header_is(headers + i, "CONTENT-LENGTH",
			   sizeof("CONTENT-LENGTH") - 1)) {
	name = "CONTENT_LENGTH";
	name_len = sizeof("CONTENT_LENGTH") - 1;
      } else {
	const char* s;
	char* d;
	size_t n;
        if (sizeof(tmp) - 5 < headers[i].name_len) {
	  hv_clear(env);
          ret = -1;
          goto done;
        }
        strcpy(tmp, "HTTP_");
        for (s = headers[i].name, n = headers[i].name_len, d = tmp + 5;
	     n != 0;
	     s++, --n, d++)
          *d = *s == '-' ? '_' : tou(*s);
        name = tmp;
        name_len = headers[i].name_len + 5;
      }
      slot = hv_fetch(env, name, name_len, 1);
      if ( !slot )
        croak("failed to create hash entry");
      if (SvOK(*slot)) {
        sv_catpvn(*slot, ", ", 2);
        sv_catpvn(*slot, headers[i].value, headers[i].value_len);
      } else
        sv_setpvn(*slot, headers[i].value, headers[i].value_len);
      last_value = *slot;
    } else {
      /* continuing lines of a mulitiline header */
      sv_catpvn(last_value, headers[i].value, headers[i].value_len);
    }
  }
  
 done:
  RETVAL = ret;
}
OUTPUT:
  RETVAL

void
parse_http_response(SV* buf, int header_format, HV* special_headers = NULL)
PPCODE:
{
  int minor_version, status;
  const char* msg;
  size_t msg_len;
  struct phr_header headers[MAX_HEADERS];
  size_t num_headers = MAX_HEADERS;
  STRLEN buf_len;
  const char* const buf_str = SvPV_const(buf, buf_len);
  size_t last_len = 0;
  int const ret             = phr_parse_response(buf_str, buf_len,
    &minor_version, &status, &msg, &msg_len, headers, &num_headers, last_len);
  SV* last_special_headers_value_sv = NULL;
  SV* last_element_value_sv         = NULL;
  size_t i;
  SV *res_headers;
  char name[MAX_HEADER_NAME_LEN]; /* temp buffer for normalized names */

  if (header_format == HEADERS_AS_HASHREF) {
    res_headers = sv_2mortal((SV*)newHV());
  } else if (header_format == HEADERS_AS_ARRAYREF) {
    res_headers = sv_2mortal((SV*)newAV());
    av_extend((AV*)res_headers, (num_headers * 2) - 1);
  } else if (header_format == HEADERS_NONE) {
    res_headers = NULL;
  }

  for (i = 0; i < num_headers; i++) {
    struct phr_header const h = headers[i];
    if (h.name != NULL) {
      SV* namesv;
      SV* valuesv;
      if(h.name_len > sizeof(name)) {
          /* skip if name_len is too long */
          continue;
      }

      normalize_response_header_name(aTHX_
        name, h.name, h.name_len);

      if(special_headers) {
          SV** const slot = hv_fetch(special_headers,
            name, h.name_len, FALSE);
          if (slot) {
            SV* const hash_value = *slot;
            sv_setpvn_mg(hash_value, h.value, h.value_len);
            last_special_headers_value_sv = hash_value;
          }
          else {
            last_special_headers_value_sv = NULL;
          }
      }

      if(header_format == HEADERS_NONE) {
          continue;
      }

      namesv  = sv_2mortal(newSVpvn_share(name, h.name_len, 0U));
      valuesv = newSVpvn_flags(
        h.value, h.value_len, SVs_TEMP);



( run in 0.936 second using v1.01-cache-2.11-cpan-5511b514fd6 )