/* Dispatch a GET request REQ, writing the response body to FD fd. If * RANGE is non-NULL, then it is the value of the Range request * header, e.g. "bytes=1-5". Returns an NE_* error code. */ static int dispatch_to_fd(ne_request *req, int fd, const char *range) { ne_session *const sess = ne_get_session(req); const ne_status *const st = ne_get_status(req); int ret; do { const char *value; ret = ne_begin_request(req); if (ret != NE_OK) break; value = ne_get_response_header(req, "Content-Range"); /* For a 206 response, check that a Content-Range header is * given which matches the Range request header. */ if (range && st->code == 206 && (value == NULL || strncmp(value, "bytes ", 6) != 0 || strcmp(range + 6, value + 6))) { ne_set_error(sess, _("Response did not include requested range")); return NE_ERROR; } if ((range && st->code == 206) || (!range && st->klass == 2)) { ret = ne_read_response_to_fd(req, fd); } else { ret = ne_discard_response(req); } if (ret == NE_OK) ret = ne_end_request(req); } while (ret == NE_RETRY); return ret; }
int ne_xml_dispatch_request(ne_request *req, ne_xml_parser *parser) { int ret; do { int parseit = 0; ret = ne_begin_request(req); if (ret) break; if (ne_get_status(req)->klass == 2) { ne_content_type ctype; if (ne_get_content_type(req, &ctype) == 0) { parseit = media_type_is_xml(&ctype); ne_free(ctype.value); } } if (parseit) ret = ne_xml_parse_response(req, parser); else ret = ne_discard_response(req); if (ret == NE_OK) ret = ne_end_request(req); } while (ret == NE_RETRY); return ret; }
static int large_get(void) { ne_request *req = ne_request_create(i_session, "GET", path); char buffer[BLOCKSIZE], origin[BLOCKSIZE * 2]; long long progress = 0; ssize_t offset = 0; ssize_t bytes; memcpy(origin, block, BLOCKSIZE); memcpy(origin + BLOCKSIZE, block, BLOCKSIZE); ONNREQ("begin large GET request", ne_begin_request(req)); ONNREQ("failed GET request", ne_get_status(req)->klass != 2); while ((bytes = ne_read_response_block(req, buffer, BLOCKSIZE)) > 0) { ONV(memcmp(origin + offset, buffer, bytes), ("byte mismatch at %" NE_FMT_LONG_LONG, progress)); offset = (offset + bytes) % BLOCKSIZE; progress += bytes; } ONNREQ("failed reading GET response", bytes < 0); ONNREQ("end large GET request", ne_end_request(req)); ne_request_destroy(req); return OK; }
static int netxml_dispatch_request(ne_request *request, ne_xml_parser *parser) { int ret; /* * Starting with neon-0.27.0 the ne_xml_dispatch_request() function will check * for a valid XML content-type (following RFC 3023 rules) in the header. * Unfortunately, (at least) the Transverse NMC doesn't follow this RFC, so * we can't use this anymore and we'll have to roll our own here. */ do { #ifndef HAVE_NE_SET_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_begin_request(request); #ifndef HAVE_NE_SET_CONNECT_TIMEOUT alarm(0); #endif if (ret != NE_OK) { break; } ret = ne_xml_parse_response(request, parser); if (ret == NE_OK) { ret = ne_end_request(request); } } while (ret == NE_RETRY); return ret; }
int s3_delete_object(S3 *s3,const char *bucket,const char *key) { ne_request *req; int err, retry; if(!s3) return -1; if(!bucket) return -1; s3_begin_session(s3); req = s3_new_request(s3,"DELETE",bucket,key,NULL,NULL); // send to server do { err = ne_begin_request(req); if(err != NE_OK) err = -EIO; else { if(ne_get_status(req)->code != 204) { s3_handle_error_response(s3,req); err = -EACCES; } retry = ne_end_request(req); } } while(retry == NE_RETRY); ne_request_destroy(req); s3_end_session(s3); return err; }
int s3_get_bucket(S3 *s3,const char *bucket, const char *prefix,const char *marker,int max_keys,const char *delimiter, const S3KeyInfoCallback *key_info_cb) { ne_request *req; int err, retry; ne_buffer *params; if(!s3) return -1; if(!bucket) return -1; params = ne_buffer_create(); if(prefix) ne_buffer_concat(params,"prefix=",prefix,"/&",NULL); if(marker) ne_buffer_concat(params,"marker=",marker,"&",NULL); if(max_keys >= 0) { char mk[16]; snprintf(mk,16,"%d",max_keys); mk[15] = 0; ne_buffer_concat(params,"max_keys=",max_keys,"&",NULL); } if(delimiter) ne_buffer_concat(params,"delimiter=",delimiter,"&",NULL); s3_begin_session(s3); req = s3_new_request(s3,"GET",bucket,NULL,params->data,NULL); ne_buffer_destroy(params); // send to server do { err = ne_begin_request(req); if(err != NE_OK) err = -EIO; else { if(ne_get_status(req)->code != 200) { s3_handle_error_response(s3,req); err = -EACCES; } else { s3->key_info.key_info_cb = key_info_cb; s3_parse_xml_response(s3, req, s3_xml_key_info_startelm, s3_xml_key_info_cdata, s3_xml_key_info_endelm, &s3->key_info ); } retry = ne_end_request(req); } } while(retry == NE_RETRY); ne_request_destroy(req); s3_end_session(s3); return err; }
/* Dispatch a GET request REQ, writing the response body to FD fd. If * RANGE is non-NULL, then it is the value of the Range request * header, e.g. "bytes=1-5". Returns an NE_* error code. */ static int dispatch_to_fd(ne_request *req, int fd, const char *range) { ne_session *const sess = ne_get_session(req); const ne_status *const st = ne_get_status(req); int ret; do { const char *value; ret = ne_begin_request(req); if (ret != NE_OK) break; value = ne_get_response_header(req, "Content-Range"); /* For a 206 response, check that a Content-Range header is * given which matches the Range request header. */ if (range && st->code == 206) { int err = 0; if (value == NULL || strncmp(value, "bytes ", 6) != 0) { err++; } else { /* If the response gives a range begin-end/total, limit * the comparison to the range itself. */ int len = strlen(value); char *cp = strchr(value, '/'); if (cp != NULL) len = (int)(cp - value); len -= 6; if (strncmp(range + 6, value + 6, len)) err++; } if (err) { ne_set_error(sess, _("Response did not include requested range")); return NE_ERROR; } } if ((range && st->code == 206) || (!range && st->klass == 2)) { ret = ne_read_response_to_fd(req, fd); } else { ret = ne_discard_response(req); } if (ret == NE_OK) ret = ne_end_request(req); } while (ret == NE_RETRY); return ret; }
int ne_xml_dispatch_request(ne_request *req, ne_xml_parser *parser) { int ret; do { ret = ne_begin_request(req); if (ret) break; if (ne_get_status(req)->klass == 2) ret = ne_xml_parse_response(req, parser); else ret = ne_discard_response(req); if (ret == NE_OK) ret = ne_end_request(req); } while (ret == NE_RETRY); return ret; }
static int read_large_response(void) { ne_session *sess; ne_request *req; off64_t count = 0; int ret; char buf[8192]; CALL(make_session(&sess, serve_large_response, NULL)); req = ne_request_create(sess, "GET", "/foo"); #ifdef NE_DEBUGGING ne_debug_init(ne_debug_stream, ne_debug_mask & ~(NE_DBG_HTTPBODY|NE_DBG_HTTP)); #endif ret = ne_begin_request(req); if (ret == NE_OK) { while ((ret = ne_read_response_block(req, buf, sizeof buf)) > 0) count += ret; if (ret == NE_OK) ret = ne_end_request(req); } #ifdef NE_DEBUGGING ne_debug_init(ne_debug_stream, ne_debug_mask & (NE_DBG_HTTPBODY|NE_DBG_HTTP)); #endif ONV(ret, ("request failed: %s", ne_get_error(sess))); ONV(count != RESPSIZE, ("response body was %" NE_FMT_OFF64_T " not %" NE_FMT_OFF64_T, count, RESPSIZE)); ne_request_destroy(req); CALL(any_2xx_request(sess, "/bar")); CALL(await_server()); ne_session_destroy(sess); return OK; }
int s3_put_object(S3 *s3,const char *bucket,const char *key,const char *content_type,int content_length,const S3ReadCallback *rcb) { ne_request *req; int err, retry; if(!s3) return -1; if(!bucket) return -1; if(!rcb) return -1; s3_begin_session(s3); req = s3_new_request(s3,"PUT",bucket,key,NULL,content_type); ne_print_request_header(req,"Content-Length","%d",content_length); #ifdef NE_LFS ne_set_request_body_provider64(req,content_length,rcb->callback,rcb->userdata); #else ne_set_request_body_provider(req,content_length,rcb->callback,rcb->userdata); #endif //ne_set_request_body_buffer(req,"hello",5); // send to server do { err = ne_begin_request(req); if(err != NE_OK) err = -EIO; else { if(ne_get_status(req)->code != 200) { s3_handle_error_response(s3,req); err = -EACCES; } retry = ne_end_request(req); } } while(retry == NE_RETRY); ne_request_destroy(req); s3_end_session(s3); return err; }
static int dispatch_to_buffer(ne_session *sess, ne_request *req, char *buf, const char *range, ssize_t *bytes_read) { const ne_status *const st = ne_get_status(req); int ret; size_t rlen; /* length of bytespec after "bytes=" */ rlen = range ? strlen(range + 6) : 0; do { const char *value; ret = ne_begin_request(req); if (ret != NE_OK) break; value = ne_get_response_header(req, "Content-Range"); /* For a 206 response, check that a Content-Range header is * given which matches the Range request header. */ if (range && st->code == 206 && (value == NULL || strncmp(value, "bytes ", 6) != 0 || strncmp(range + 6, value + 6, rlen) || (range[5 + rlen] != '-' && value[6 + rlen] != '/'))) { ne_set_error(sess, "Response did not include requested range"); return NE_ERROR; } if ((range && st->code == 206) || (!range && st->klass == 2)) { ret = ne_read_response_to_buf(req, buf, bytes_read); } else { ret = ne_discard_response(req); } if (ret == NE_OK) ret = ne_end_request(req); } while (ret == NE_RETRY); return ret; }
int s3_get_object(S3 *s3,const char *bucket,const char *key,const S3WriteCallback *wcb) { ne_request *req; int err, retry; if(!s3) return -1; if(!bucket) return -1; if(!wcb) return -1; s3_begin_session(s3); req = s3_new_request(s3,"GET",bucket,key,NULL,NULL); // send to server do { err = ne_begin_request(req); if(err != NE_OK) err = -EIO; else { if(ne_get_status(req)->code != 200) { s3_handle_error_response(s3,req); if(ne_get_status(req)->code == 404) err = -ENOENT; else err = -EACCES; } else { char buffer[4096]; size_t bytes_read; while((bytes_read = ne_read_response_block(req,buffer,4096)) > 0) { wcb->callback(wcb->userdata,buffer,bytes_read); } } retry = ne_end_request(req); } } while(retry == NE_RETRY); ne_request_destroy(req); s3_end_session(s3); return err; }
static int open_request (struct neon_handle * handle, uint64_t startbyte) { int ret; const ne_status * status; ne_uri * rediruri; if (handle->purl->query && * (handle->purl->query)) { SCONCAT3 (tmp, handle->purl->path, "?", handle->purl->query); handle->request = ne_request_create (handle->session, "GET", tmp); } else handle->request = ne_request_create (handle->session, "GET", handle->purl->path); if (startbyte > 0) ne_print_request_header (handle->request, "Range", "bytes=%"PRIu64"-", startbyte); ne_print_request_header (handle->request, "Icy-MetaData", "1"); /* Try to connect to the server. */ _DEBUG ("<%p> Connecting...", handle); ret = ne_begin_request (handle->request); status = ne_get_status (handle->request); _DEBUG ("<%p> Return: %d, Status: %d", handle, ret, status->code); if (ret == NE_OK) { switch (status->code) { case 401: /* Authorization required. Reconnect to authenticate */ _DEBUG ("Reconnecting due to 401"); ne_end_request (handle->request); ret = ne_begin_request (handle->request); break; case 301: case 302: case 303: case 307: /* Redirect encountered. Reconnect. */ ne_end_request (handle->request); ret = NE_REDIRECT; break; case 407: /* Proxy auth required. Reconnect to authenticate */ _DEBUG ("Reconnecting due to 407"); ne_end_request (handle->request); ret = ne_begin_request (handle->request); break; } } switch (ret) { case NE_OK: if (status->code > 199 && status->code < 300) { /* URL opened OK */ _DEBUG ("<%p> URL opened OK", handle); handle->content_start = startbyte; handle->pos = startbyte; handle_headers (handle); return 0; } break; case NE_REDIRECT: /* We hit a redirect. Handle it. */ _DEBUG ("<%p> Redirect encountered", handle); handle->redircount += 1; rediruri = (ne_uri *) ne_redirect_location (handle->session); ne_request_destroy (handle->request); handle->request = NULL; if (! rediruri) { _ERROR ("<%p> Could not parse redirect response", (void *) handle); return -1; } ne_uri_free (handle->purl); ne_uri_copy (handle->purl, rediruri); return 1; } /* Something went wrong. */ _ERROR ("<%p> Could not open URL: %d (%d)", (void *) handle, ret, status->code); if (ret) _ERROR ("<%p> neon error string: %s", (void *) handle, ne_get_error (handle->session)); ne_request_destroy (handle->request); handle->request = NULL; return -1; }
static int netxml_alarm_subscribe(const char *page) { int ret, port = -1, secret = -1; char buf[LARGEBUF], *s; ne_request *request; ne_sock_addr *addr; const ne_inet_addr *ai; char resp_buf[LARGEBUF]; /* Clear response buffer */ memset(resp_buf, 0, sizeof(resp_buf)); upsdebugx(2, "%s: %s", __func__, page); sock = ne_sock_create(); if (gethostname(buf, sizeof(buf)) == 0) { dstate_setinfo("driver.hostname", "%s", buf); } else { dstate_setinfo("driver.hostname", "<unknown>"); } #ifdef HAVE_NE_SOCK_CONNECT_TIMEOUT ne_sock_connect_timeout(sock, timeout); #endif ne_sock_read_timeout(sock, 1); netxml_get_page(subdriver->configure); snprintf(buf, sizeof(buf), "<?xml version=\"1.0\"?>\n"); snprintfcat(buf, sizeof(buf), "<Subscribe>\n"); snprintfcat(buf, sizeof(buf), "<Class>%s v%s</Class>\n", progname, DRIVER_VERSION); snprintfcat(buf, sizeof(buf), "<Type>connected socket</Type>\n"); snprintfcat(buf, sizeof(buf), "<HostName>%s</HostName>\n", dstate_getinfo("driver.hostname")); snprintfcat(buf, sizeof(buf), "<XMLClientParameters>\n"); snprintfcat(buf, sizeof(buf), "<ShutdownDuration>%d</ShutdownDuration>\n", shutdown_duration); if( shutdown_timer > 0 ) { snprintfcat(buf, sizeof(buf), "<ShutdownTimer>%d</ShutdownTimer>\r\n", shutdown_timer); } else { snprintfcat(buf, sizeof(buf), "<ShutdownTimer>NONE</ShutdownTimer>\n"); } snprintfcat(buf, sizeof(buf), "<AutoConfig>LOCAL</AutoConfig>\n"); snprintfcat(buf, sizeof(buf), "<OutletGroup>1</OutletGroup>\n"); snprintfcat(buf, sizeof(buf), "</XMLClientParameters>\n"); snprintfcat(buf, sizeof(buf), "<Warning></Warning>\n"); snprintfcat(buf, sizeof(buf), "</Subscribe>\n"); /* now send subscription message setting all the proper flags */ request = ne_request_create(session, "POST", page); ne_set_request_body_buffer(request, buf, strlen(buf)); /* as the NMC reply is not xml standard compliant let's parse it this way */ do { #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_begin_request(request); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(0); #endif if (ret != NE_OK) { break; } ret = ne_read_response_block(request, resp_buf, sizeof(resp_buf)); if (ret == NE_OK) { ret = ne_end_request(request); } } while (ret == NE_RETRY); ne_request_destroy(request); /* due to different formats used by the various NMCs, we need to\ break up the reply in lines and parse each one separately */ for (s = strtok(resp_buf, "\r\n"); s != NULL; s = strtok(NULL, "\r\n")) { upsdebugx(2, "%s: parsing %s", __func__, s); if (!strncasecmp(s, "<Port>", 6) && (sscanf(s+6, "%u", &port) != 1)) { return NE_RETRY; } if (!strncasecmp(s, "<Secret>", 8) && (sscanf(s+8, "%u", &secret) != 1)) { return NE_RETRY; } } if ((port == -1) || (secret == -1)) { upsdebugx(2, "%s: parsing initial subcription failed", __func__); return NE_RETRY; } /* Resolve the given hostname. 'flags' must be zero. Hex * string IPv6 addresses (e.g. `::1') may be enclosed in brackets * (e.g. `[::1]'). */ addr = ne_addr_resolve(uri.host, 0); /* Returns zero if name resolution was successful, non-zero on * error. */ if (ne_addr_result(addr) != 0) { upsdebugx(2, "%s: name resolution failure on %s: %s", __func__, uri.host, ne_addr_error(addr, buf, sizeof(buf))); ne_addr_destroy(addr); return NE_RETRY; } for (ai = ne_addr_first(addr); ai != NULL; ai = ne_addr_next(addr)) { upsdebugx(2, "%s: connecting to host %s port %d", __func__, ne_iaddr_print(ai, buf, sizeof(buf)), port); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_sock_connect(sock, ai, port); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(0); #endif if (ret == NE_OK) { upsdebugx(2, "%s: connection to %s open on fd %d", __func__, uri.host, ne_sock_fd(sock)); break; } } ne_addr_destroy(addr); if (ai == NULL) { upsdebugx(2, "%s: failed to create listening socket", __func__); return NE_RETRY; } snprintf(buf, sizeof(buf), "<Subscription Identification=\"%u\"></Subscription>", secret); ret = ne_sock_fullwrite(sock, buf, strlen(buf) + 1); if (ret != NE_OK) { upsdebugx(2, "%s: send failed: %s", __func__, ne_sock_error(sock)); return NE_RETRY; } ret = ne_sock_read(sock, buf, sizeof(buf)); if (ret < 1) { upsdebugx(2, "%s: read failed: %s", __func__, ne_sock_error(sock)); return NE_RETRY; } if (strcasecmp(buf, "<Subscription Answer=\"ok\"></Subscription>")) { upsdebugx(2, "%s: subscription rejected", __func__); return NE_RETRY; } upslogx(LOG_INFO, "NSM connection to '%s' established", uri.host); return NE_OK; }
/** * \brief Send HTTP request over a session * * The function creates HTTP request, sends it and reads-out the response. * * \param[in] session HTTP session * \param[in] method Request method * \param[in] uri Request URI * \param[in] ct Request content type (optional, \c NULL accepted) * \param[in] req_body Request body (optional, \c NULL is accepted) * \param[out] resp_body Response body (optional, \c NULL is accepted) * * \return HTTP status code if response was sent, 0 on send error */ static int send_http_request( ne_session *session, const char *method, const char *uri, const char *ct, ne_buffer *req_body, ne_buffer *resp_body) { int resp_code = 0; ne_request *req = NULL; /* Create request */ req = ne_request_create(session, method, uri); /* Neon claims that request creation is always successful */ assert(NULL != req); do { /* Pragmatic do ... while (0) loop allowing breaks on error */ const ne_status *req_st; /* Set Content-Type */ if (NULL != ct) ne_add_request_header(req, "Content-Type", ct); /* Set request body */ if (NULL != req_body) /* BEWARE: The terminating '\0' byte is "used", too */ ne_set_request_body_buffer(req, req_body->data, req_body->used - 1); /* Send request */ int status = ne_begin_request(req); if (NE_OK != status) { break; } /* Read response */ assert(NE_OK == status); for (;;) { char buff[512]; ssize_t read; read = ne_read_response_block(req, buff, sizeof(buff)); /* Read failure */ if (0 > read) { status = NE_ERROR; break; } if (0 == read) break; if (NULL != resp_body) ne_buffer_append(resp_body, buff, read); } if (NE_OK != status) { break; } /* Request served */ ne_end_request(req); /* Get response code */ req_st = ne_get_status(req); assert(NULL != req_st); resp_code = req_st->code; } while (0); /* end of do ... while (0) pragmatic loop */ if (NULL != req) ne_request_destroy(req); return resp_code; }
/* Try to send the HTTP request to the Icecast server, and if possible deals with * all the probable redirections (HTTP status code == 3xx) */ static gint gst_neonhttp_src_send_request_and_redirect (GstNeonhttpSrc * src, ne_session ** ses, ne_request ** req, gint64 offset, gboolean do_redir) { ne_session *session = NULL; ne_request *request = NULL; gchar **c; gint res; gint http_status = 0; guint request_count = 0; do { if (src->proxy.host && src->proxy.port) { session = ne_session_create (src->uri.scheme, src->uri.host, src->uri.port); ne_session_proxy (session, src->proxy.host, src->proxy.port); } else if (src->proxy.host || src->proxy.port) { /* both proxy host and port must be specified or none */ return HTTP_REQUEST_WRONG_PROXY; } else { session = ne_session_create (src->uri.scheme, src->uri.host, src->uri.port); } if (src->connect_timeout > 0) { ne_set_connect_timeout (session, src->connect_timeout); } if (src->read_timeout > 0) { ne_set_read_timeout (session, src->read_timeout); } ne_set_session_flag (session, NE_SESSFLAG_ICYPROTO, 1); ne_ssl_set_verify (session, ssl_verify_callback, src); request = ne_request_create (session, "GET", src->query_string); if (src->user_agent) { ne_add_request_header (request, "User-Agent", src->user_agent); } for (c = src->cookies; c != NULL && *c != NULL; ++c) { GST_INFO ("Adding header Cookie : %s", *c); ne_add_request_header (request, "Cookies", *c); } if (src->iradio_mode) ne_add_request_header (request, "icy-metadata", "1"); if (offset > 0) { ne_print_request_header (request, "Range", "bytes=%" G_GINT64_FORMAT "-", offset); } res = ne_begin_request (request); if (res == NE_OK) { /* When the HTTP status code is 3xx, it is not the SHOUTcast streaming content yet; * Reload the HTTP request with a new URI value */ http_status = ne_get_status (request)->code; if (STATUS_IS_REDIRECTION (http_status) && do_redir) { const gchar *redir; /* the new URI value to go when redirecting can be found on the 'Location' HTTP header */ redir = ne_get_response_header (request, "Location"); if (redir != NULL) { ne_uri_free (&src->uri); gst_neonhttp_src_set_location (src, redir, NULL); GST_LOG_OBJECT (src, "Got HTTP Status Code %d", http_status); GST_LOG_OBJECT (src, "Using 'Location' header [%s]", src->uri.host); } } } if ((res != NE_OK) || (offset == 0 && http_status != 200) || (offset > 0 && http_status != 206 && !STATUS_IS_REDIRECTION (http_status))) { ne_request_destroy (request); request = NULL; ne_close_connection (session); ne_session_destroy (session); session = NULL; if (offset > 0 && http_status != 206 && !STATUS_IS_REDIRECTION (http_status)) { src->seekable = FALSE; } } /* if - NE_OK */ if (STATUS_IS_REDIRECTION (http_status) && do_redir) { ++request_count; GST_LOG_OBJECT (src, "redirect request_count is now %d", request_count); if (request_count < MAX_HTTP_REDIRECTS_NUMBER && do_redir) { GST_INFO_OBJECT (src, "Redirecting to %s", src->uri.host); } else { GST_WARNING_OBJECT (src, "Will not redirect, try again with a " "different URI or redirect location %s", src->uri.host); } /* FIXME: when not redirecting automatically, shouldn't we post a * redirect element message on the bus? */ } /* do the redirect, go back to send another HTTP request now using the 'Location' */ } while (do_redir && (request_count < MAX_HTTP_REDIRECTS_NUMBER) && STATUS_IS_REDIRECTION (http_status)); if (session) { *ses = session; *req = request; } return res; }