static int send_request(char *method, const char *path, FILE *fp, xmlParserCtxtPtr xmlctx, curl_slist *extra_headers) { long response = -1; int tries = 0; // retry on failures for (tries = 0; tries < REQUEST_RETRIES; tries++) { CURL *curl = get_connection(path); curl_slist *headers = NULL; add_header(&headers, "X-Auth-Token", storage_token); curl_easy_setopt(curl, CURLOPT_VERBOSE, debug); if (!strcasecmp(method, "MKDIR")) { curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); add_header(&headers, "Content-Type", "application/directory"); } else if (!strcasecmp(method, "PUT") && fp) { rewind(fp); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size(fileno(fp))); curl_easy_setopt(curl, CURLOPT_READDATA, fp); } else if (!strcasecmp(method, "GET")) { if (fp) { rewind(fp); // make sure the file is ready for a-writin' fflush(fp); ftruncate(fileno(fp), 0); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); } else if (xmlctx) { curl_easy_setopt(curl, CURLOPT_WRITEDATA, xmlctx); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &xml_dispatch); } } else curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method); /* add the headers from extra_headers if any */ curl_slist *extra; for (extra = extra_headers; extra; extra = extra->next) { debugf("adding header: %s", extra->data); headers = curl_slist_append(headers, extra->data); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); curl_slist_free_all(headers); return_connection(curl); if (response >= 200 && response < 400) return response; sleep(8 << tries); // backoff if (response == 401 && !cloudfs_connect(0, 0, 0, 0)) // re-authenticate on 401s return response; if (xmlctx) xmlCtxtResetPush(xmlctx, NULL, 0, NULL, NULL); } return response; }
static int send_request(char *method, const char *path, FILE *fp, xmlParserCtxtPtr xmlctx, curl_slist *extra_headers) { char url[MAX_URL_SIZE]; char *slash; long response = -1; int tries = 0; if (!storage_url[0]) { debugf("send_request with no storage_url?"); abort(); } while ((slash = strstr(path, "%2F")) || (slash = strstr(path, "%2f"))) { *slash = '/'; memmove(slash+1, slash+3, strlen(slash+3)+1); } while (*path == '/') path++; snprintf(url, sizeof(url), "%s/%s", storage_url, path); // retry on failures for (tries = 0; tries < REQUEST_RETRIES; tries++) { CURL *curl = get_connection(path); if (rhel5_mode) curl_easy_setopt(curl, CURLOPT_CAINFO, RHEL5_CERTIFICATE_FILE); curl_slist *headers = NULL; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_HEADER, 0); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, verify_ssl); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_VERBOSE, debug); add_header(&headers, "X-Auth-Token", storage_token); if (!strcasecmp(method, "MKDIR")) { curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); add_header(&headers, "Content-Type", "application/directory"); } else if (!strcasecmp(method, "PUT") && fp) { rewind(fp); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(curl, CURLOPT_INFILESIZE, cloudfs_file_size(fileno(fp))); curl_easy_setopt(curl, CURLOPT_READDATA, fp); } else if (!strcasecmp(method, "GET")) { if (fp) { rewind(fp); // make sure the file is ready for a-writin' fflush(fp); if (ftruncate(fileno(fp), 0) < 0) { debugf("ftruncate failed. I don't know what to do about that."); abort(); } curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); } else if (xmlctx) { curl_easy_setopt(curl, CURLOPT_WRITEDATA, xmlctx); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &xml_dispatch); } } else curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method); /* add the headers from extra_headers if any */ curl_slist *extra; for (extra = extra_headers; extra; extra = extra->next) { debugf("adding header: %s", extra->data); headers = curl_slist_append(headers, extra->data); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); curl_slist_free_all(headers); curl_easy_reset(curl); return_connection(curl); if (response >= 200 && response < 400) return response; sleep(8 << tries); // backoff if (response == 401 && !cloudfs_connect()) // re-authenticate on 401s return response; if (xmlctx) xmlCtxtResetPush(xmlctx, NULL, 0, NULL, NULL); } return response; }
static int exmpp_xml_control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen) { struct exmpp_xml_data *edd; ei_x_buff *to_return; ErlDrvBinary *bin; int size, ret; edd = (struct exmpp_xml_data *)drv_data; size = 0; bin = NULL; to_return = NULL; switch (command) { /* * Parsing. */ case COMMAND_PARSE: case COMMAND_PARSE_FINAL: if (edd->parser == NULL) { /* Start a parser. */ if (create_parser(edd) != 0) { to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_ERROR; ei_x_encode_atom(to_return, "parser_setup_failed"); break; } } /* Control the total size of data to parse. */ if (!is_data_size_under_limit(&edd->ctx, len)) { to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_ERROR; ei_x_encode_atom(to_return, "stanza_too_big"); break; } /* Run XML document parsing. */ ret = xmlParseChunk(edd->parser, buf, len, command == COMMAND_PARSE_FINAL); if (ret > 0) { xmlError *error; /* An error occured during parsing; most probably, * XML wasn't well-formed. */ error = xmlCtxtGetLastError(edd->parser); to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_ERROR; ei_x_encode_tuple_header(to_return, 2); ei_x_encode_atom(to_return, "parsing_failed"); ei_x_encode_tuple_header(to_return, 2); ei_x_encode_long(to_return, error->code); ei_x_encode_string(to_return, error->message); break; } /* Return the complete tree(s). */ ret = RET_OK; if (edd->ctx.complete_trees_ready) { /* Terminate the complete trees list. */ ei_x_encode_empty_list(edd->ctx.complete_trees); to_return = edd->ctx.complete_trees; size = 1 + to_return->index; bin = driver_alloc_binary(size); if (bin == NULL) return (-1); bin->orig_bytes[0] = (char)ret; memcpy(bin->orig_bytes + 1, to_return->buff, to_return->index); } else { /* We need more data to produce a tree. */ to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ei_x_encode_atom(to_return, command == COMMAND_PARSE ? "continue" : "done"); } if (command == COMMAND_PARSE) { /* Update the size of processed data. */ add_data_size(&edd->ctx, len); /* Reset the complete trees list. */ reset_complete_trees(&edd->ctx); } else { /* We're done with the parser. */ destroy_parser(edd); } break; case COMMAND_RESET_PARSER: if (edd->parser != NULL) { xmlCtxtResetPush(edd->parser, NULL, 0, NULL, NULL); } ret = RET_OK; break; /* * Misc. */ case COMMAND_PORT_REVISION: /* Store the revision in the buffer. */ to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_OK; ei_x_encode_string(to_return, "$Revision: 809 $"); break; default: /* Other commands are handled in 'exmpp_xml.c' */ to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = control(&edd->ctx, command, buf, to_return); if (ret < 0) return (-1); } if (bin == NULL) { if (to_return != NULL) { size = 1 + to_return->index; bin = driver_alloc_binary(size); if (bin == NULL) return (-1); bin->orig_bytes[0] = (char)ret; if (to_return->index > 0) memcpy(bin->orig_bytes + 1, to_return->buff, to_return->index); exmpp_free_xbuf(to_return); } else { /* The command called doesn't return anything. */ size = 1; bin = driver_alloc_binary(size); bin->orig_bytes[0] = RET_OK; } } /* Set the returned buffer. */ *rbuf = (char *)bin; /* Return the size of this buffer. */ return (size); }