static void install_content_reader( ne_request *req, void *userdata, const ne_status *status ) { const char *enc = NULL; struct transfer_context *writeCtx = userdata; (void) status; if( !writeCtx ) { DEBUG_WEBDAV("Error: install_content_reader called without valid write context!"); return; } enc = ne_get_response_header( req, "Content-Encoding" ); if( status && status->code != 200 ) { DEBUG_WEBDAV("Content encoding ist <%s> with status %d", enc ? enc : "empty", status ? status->code : -1 ); } if( enc && c_streq( enc, "gzip" )) { writeCtx->decompress = ne_decompress_reader( req, ne_accept_2xx, compress_reader, /* reader callback */ (void*) writeCtx ); /* userdata */ } else { ne_add_response_body_reader( req, ne_accept_2xx, uncompress_reader, (void*) writeCtx ); writeCtx->decompress = NULL; } }
int ne_getmodtime(ne_session *sess, const char *uri, time_t *modtime) { ne_request *req = ne_request_create(sess, "HEAD", uri); const char *value; int ret; ret = ne_request_dispatch(req); value = ne_get_response_header(req, "Last-Modified"); if (ret == NE_OK && ne_get_status(req)->klass != 2) { *modtime = -1; ret = NE_ERROR; } else if (value) { *modtime = ne_httpdate_parse(value); } else { *modtime = -1; } ne_request_destroy(req); return ret; }
/* 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; }
static int accept(void* userdata, ne_request* req, const ne_status* st) { ne_userdata* u = reinterpret_cast<ne_userdata*>(userdata); auto len = ne_get_response_header(req, "Content-Length"); (void)u; (void)len; return true; }
const char * svn_ra_neon__request_get_location(svn_ra_neon__request_t *request, apr_pool_t *pool) { const char *val = ne_get_response_header(request->ne_req, "Location"); return val ? svn_urlpath__canonicalize(val, pool) : NULL; }
int s3_head_object(S3 *s3,const char *bucket,const char *key,S3ObjectInfo *oi) { ne_request *req; int err; if(!s3) return -1; if(!bucket) return -1; s3_begin_session(s3); req = s3_new_request(s3,"HEAD",bucket,key,NULL,NULL); // send to server err = ne_request_dispatch(req); if(err != NE_OK) err = -EIO; 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 if(oi) { const char *str; str = ne_get_response_header(req,"Content-Length"); if(str) oi->content_length = strtol(str,NULL,10); str = ne_get_response_header(req,"Content-Type"); if(str) { strncpy(oi->content_type,str,31); oi->content_type[31] = 0; } str = ne_get_response_header(req,"ETag"); if(str) { strncpy(oi->etag,str,79); oi->etag[79] = 0; } } ne_request_destroy(req); s3_end_session(s3); return err; }
int ne_get_content_type(ne_request *req, ne_content_type *ct) { const char *value; char *sep, *stype; value = ne_get_response_header(req, "Content-Type"); if (value == NULL || strchr(value, '/') == NULL) { return -1; } ct->value = ne_strdup(value); stype = strchr(ct->value, '/'); *stype++ = '\0'; ct->type = ct->value; ct->charset = NULL; sep = strchr(stype, ';'); if (sep) { char *tok; /* look for the charset parameter. TODO; probably better to * hand-carve a parser than use ne_token/strstr/shave here. */ *sep++ = '\0'; do { tok = ne_qtoken(&sep, ';', "\"\'"); if (tok) { tok = strstr(tok, "charset="); if (tok) ct->charset = ne_shave(tok+8, "\"\'"); } else { break; } } while (sep != NULL); } /* set subtype, losing any trailing whitespace */ ct->subtype = ne_shave(stype, " \t"); if (ct->charset == NULL && ne_strcasecmp(ct->type, "text") == 0) { /* 3280§3.1: text/xml without charset implies us-ascii. */ if (ne_strcasecmp(ct->subtype, "xml") == 0) ct->charset = "us-ascii"; /* 2616§3.7.1: subtypes of text/ default to charset ISO-8859-1. */ else ct->charset = "ISO-8859-1"; } return 0; }
/* 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_options(ne_session *sess, const char *uri, ne_server_capabilities *caps) { ne_request *req = ne_request_create(sess, "OPTIONS", uri); int ret = ne_request_dispatch(req); const char *header = ne_get_response_header(req, "DAV"); if (header) parse_dav_header(header, caps); if (ret == NE_OK && ne_get_status(req)->klass != 2) { ret = NE_ERROR; } ne_request_destroy(req); return ret; }
static int lk_startelm(void *userdata, int parent, const char *nspace, const char *name, const char **atts) { struct lock_ctx *ctx = userdata; int id; NE_DEBUG_WINSCP_CONTEXT(ne_get_session(ctx->req)); id = ne_xml_mapid(element_map, NE_XML_MAPLEN(element_map), nspace, name); NE_DEBUG(NE_DBG_LOCKS, "lk_startelm: %s => %d\n", name, id); if (id == 0) return NE_XML_DECLINE; if (parent == 0 && ctx->token == NULL) { const char *token = ne_get_response_header(ctx->req, "Lock-Token"); /* at the root element; retrieve the Lock-Token header, * and bail if it wasn't given. */ if (token == NULL) { ne_xml_set_error(ctx->parser, _("LOCK response missing Lock-Token header")); return NE_XML_ABORT; } if (token[0] == '<') token++; ctx->token = ne_strdup(token); ne_shave(ctx->token, ">"); NE_DEBUG(NE_DBG_LOCKS, "lk_startelm: Finding token %s\n", ctx->token); } /* TODO: only accept 'prop' as root for LOCK response */ if (!can_accept(parent, id)) return NE_XML_DECLINE; if (id == ELM_activelock && !ctx->found) { /* a new activelock */ ne_lock_free(&ctx->active); memset(&ctx->active, 0, sizeof ctx->active); ctx->active.timeout = NE_TIMEOUT_INVALID; } ne_buffer_clear(ctx->cdata); return id; }
static int post_send_hook(ne_request *req, void *userdata, const ne_status *status) { const char *location; (void) userdata; (void) status; location = ne_get_response_header(req, "Location"); if( !location ) return NE_OK; if( dav_session.redir_callback ) { if( dav_session.redir_callback( dav_session.csync_ctx, location ) ) { return NE_REDIRECT; } else { return NE_RETRY; } } return NE_REDIRECT; }
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; }
/* Store in RAS the capabilities discovered from REQ's headers. Use POOL for temporary allocation only. */ static void parse_capabilities(ne_request *req, svn_ra_neon__session_t *ras, apr_pool_t *pool) { const char *header_value; /* Start out assuming all capabilities are unsupported. */ apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_DEPTH, APR_HASH_KEY_STRING, capability_no); apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING, capability_no); apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS, APR_HASH_KEY_STRING, capability_no); /* Then find out which ones are supported. */ header_value = ne_get_response_header(req, "dav"); if (header_value) { /* Multiple headers of the same name will have been merged together by the time we see them (either by an intermediary, as is permitted in HTTP, or by neon) -- merged in the sense that if a header "foo" appears multiple times, all the values will be concatenated together, with spaces at the splice points. For example, if the server sent: DAV: 1,2 DAV: version-control,checkout,working-resource DAV: merge,baseline,activity,version-controlled-collection DAV: http://subversion.tigris.org/xmlns/dav/svn/depth Here we might see: header_value == "1,2, version-control,checkout,working-resource, merge,baseline,activity,version-controlled-collection, http://subversion.tigris.org/xmlns/dav/svn/depth, <http://apache.org/dav/propset/fs/1>" (Deliberately not line-wrapping that, so you can see what we're about to parse.) */ apr_array_header_t *vals = svn_cstring_split(header_value, ",", TRUE, pool); /* Right now we only have a few capabilities to detect, so just seek for them directly. This could be written slightly more efficiently, but that wouldn't be worth it until we have many more capabilities. */ if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals)) apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_DEPTH, APR_HASH_KEY_STRING, capability_yes); if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_MERGEINFO, vals)) /* The server doesn't know what repository we're referring to, so it can't just say capability_yes. */ apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING, capability_server_yes); if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_LOG_REVPROPS, vals)) apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS, APR_HASH_KEY_STRING, capability_yes); if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals)) apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY, APR_HASH_KEY_STRING, capability_yes); } }
/* create a socket for connecting to remote server */ static gboolean gst_neonhttp_src_start (GstBaseSrc * bsrc) { GstNeonhttpSrc *src = GST_NEONHTTP_SRC (bsrc); const gchar *content_length; gint res; #ifndef GST_DISABLE_GST_DEBUG if (src->neon_http_debug) ne_debug_init (stderr, NE_DBG_HTTP); #endif ne_oom_callback (oom_callback); res = ne_sock_init (); if (res != 0) goto init_failed; res = gst_neonhttp_src_send_request_and_redirect (src, &src->session, &src->request, 0, src->automatic_redirect); if (res != NE_OK || !src->session) { if (res == HTTP_SOCKET_ERROR) { goto socket_error; } else if (res == HTTP_REQUEST_WRONG_PROXY) { goto wrong_proxy; } else { goto begin_req_failed; } } content_length = ne_get_response_header (src->request, "Content-Length"); if (content_length) src->content_size = g_ascii_strtoull (content_length, NULL, 10); else src->content_size = -1; if (src->iradio_mode) { /* Icecast stuff */ const gchar *str_value; gint gint_value; str_value = ne_get_response_header (src->request, "icy-metaint"); if (str_value) { if (sscanf (str_value, "%d", &gint_value) == 1) { if (src->icy_caps) { gst_caps_unref (src->icy_caps); src->icy_caps = NULL; } src->icy_metaint = gint_value; src->icy_caps = gst_caps_new_simple ("application/x-icy", "metadata-interval", G_TYPE_INT, src->icy_metaint, NULL); } } str_value = ne_get_response_header (src->request, "icy-name"); if (str_value) { if (src->iradio_name) { g_free (src->iradio_name); src->iradio_name = NULL; } src->iradio_name = gst_neonhttp_src_unicodify (str_value); } str_value = ne_get_response_header (src->request, "icy-genre"); if (str_value) { if (src->iradio_genre) { g_free (src->iradio_genre); src->iradio_genre = NULL; } src->iradio_genre = gst_neonhttp_src_unicodify (str_value); } str_value = ne_get_response_header (src->request, "icy-url"); if (str_value) { if (src->iradio_url) { g_free (src->iradio_url); src->iradio_url = NULL; } src->iradio_url = gst_neonhttp_src_unicodify (str_value); } } return TRUE; /* ERRORS */ init_failed: { GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), ("ne_sock_init() failed: %d", res)); return FALSE; } socket_error: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("HTTP Request failed when opening socket: %d", res)); return FALSE; } wrong_proxy: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Proxy Server URI is invalid - make sure that either both proxy host " "and port are specified or neither.")); return FALSE; } begin_req_failed: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Could not begin request: %d", res)); return FALSE; } }
static int ah_post_send(ne_request *req, void *cookie, const ne_status *status) { auth_session *sess = cookie; struct auth_request *areq = ne_get_request_private(req, sess->spec->id); const char *auth_hdr, *auth_info_hdr; int ret = NE_OK; if (!areq) return NE_OK; auth_hdr = ne_get_response_header(req, sess->spec->resp_hdr); auth_info_hdr = ne_get_response_header(req, sess->spec->resp_info_hdr); if (sess->context == AUTH_CONNECT && status->code == 401 && !auth_hdr) { /* Some broken proxies issue a 401 as a proxy auth challenge * to a CONNECT request; handle this here. */ auth_hdr = ne_get_response_header(req, "WWW-Authenticate"); auth_info_hdr = NULL; } #ifdef HAVE_GSSAPI /* whatever happens: forget the GSSAPI token cached thus far */ if (sess->gssapi_token) { ne_free(sess->gssapi_token); sess->gssapi_token = NULL; } #endif NE_DEBUG(NE_DBG_HTTPAUTH, "ah_post_send (#%d), code is %d (want %d), %s is %s\n", sess->attempt, status->code, sess->spec->status_code, sess->spec->resp_hdr, auth_hdr ? auth_hdr : "(none)"); if (auth_info_hdr && sess->scheme == auth_scheme_digest) { if (verify_digest_response(areq, sess, auth_info_hdr)) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response authentication invalid.\n"); ne_set_error(sess->sess, "%s", _(sess->spec->fail_msg)); ret = NE_ERROR; } } #ifdef HAVE_GSSAPI /* one must wonder... has Mr Brezak actually read RFC2617? */ else if (sess->scheme == auth_scheme_gssapi && (status->klass == 2 || status->klass == 3) && auth_hdr) { char *hdr = ne_strdup(auth_hdr); if (verify_negotiate_response(sess, hdr)) { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Mutual auth failed.\n"); ret = NE_ERROR; } ne_free(hdr); } #endif /* HAVE_GSSAPI */ else if ((status->code == sess->spec->status_code || (status->code == 401 && sess->context == AUTH_CONNECT)) && auth_hdr) { /* note above: allow a 401 in response to a CONNECT request * from a proxy since some buggy proxies send that. */ NE_DEBUG(NE_DBG_HTTPAUTH, "Got challenge (code %d).\n", status->code); if (!auth_challenge(sess, auth_hdr)) { ret = NE_RETRY; } else { clean_session(sess); ret = sess->spec->fail_code; } } #ifdef HAVE_SSPI else if (sess->sspi_context) { ne_sspi_clear_context(sess->sspi_context); } #endif return ret; }
/* * perform one transfer of one block. * returns HBF_TRANSFER_SUCCESS if the transfer of this block was a success * returns HBF_SUCCESS if the server aknoweldge that he received all the blocks */ static int _hbf_dav_request(hbf_transfer_t *transfer, ne_request *req, int fd, hbf_block_t *blk ) { Hbf_State state = HBF_TRANSFER_SUCCESS; int res; const ne_status *req_status = NULL; const char *etag = NULL; (void) transfer; if( ! (blk && req) ) return HBF_PARAM_FAIL; ne_set_request_body_fd(req, fd, blk->start, blk->size); DEBUG_HBF("Block: %d , Start: %" PRId64 " and Size: %" PRId64 "", blk->seq_number, blk->start, blk->size ); res = ne_request_dispatch(req); req_status = ne_get_status( req ); switch(res) { case NE_OK: blk->state = HBF_TRANSFER_FAILED; state = HBF_FAIL; etag = 0; if( req_status->klass == 2 ) { state = HBF_TRANSFER_SUCCESS; blk->state = HBF_TRANSFER_SUCCESS; etag = ne_get_response_header(req, "ETag"); if (etag && etag[0]) { /* When there is an etag, it means the transfer was complete */ state = HBF_SUCCESS; if( etag[0] == '"' && etag[ strlen(etag)-1] == '"') { int len = strlen( etag )-2; blk->etag = malloc( len+1 ); strncpy( blk->etag, etag+1, len ); blk->etag[len] = '\0'; } else { blk->etag = strdup( etag ); } } else { /* DEBUG_HBF("OOOOOOOO No etag returned!"); */ } /* check if the server was able to set the mtime already. */ etag = ne_get_response_header(req, "X-OC-MTime"); if( etag && strcmp(etag, "accepted") == 0 ) { /* the server acknowledged that the mtime was set. */ transfer->modtime_accepted = 1; } etag = ne_get_response_header(req, "OC-FileID"); if( etag ) { transfer->file_id = strdup( etag ); } } break; case NE_AUTH: state = HBF_AUTH_FAIL; blk->state = HBF_TRANSFER_FAILED; break; case NE_PROXYAUTH: state = HBF_PROXY_AUTH_FAIL; blk->state = HBF_TRANSFER_FAILED; break; case NE_CONNECT: state = HBF_CONNECT_FAIL; blk->state = HBF_TRANSFER_FAILED; break; case NE_TIMEOUT: state = HBF_TIMEOUT_FAIL; blk->state = HBF_TRANSFER_FAILED; break; case NE_ERROR: state = HBF_FAIL; blk->state = HBF_TRANSFER_FAILED; break; } blk->http_result_code = req_status->code; if( req_status->reason_phrase ) { blk->http_error_msg = strdup(req_status->reason_phrase); } return state; }
/* Callback which is passed blocks of the response body. */ static int gz_reader(void *ud, const char *buf, size_t len) { ne_decompress *ctx = ud; const char *zbuf; size_t count; const char *hdr; if (len == 0) { /* End of response: */ switch (ctx->state) { case NE_Z_BEFORE_DATA: hdr = ne_get_response_header(ctx->request, "Content-Encoding"); if (hdr && strcasecmp(hdr, "gzip") == 0) { /* response was truncated: return error. */ break; } /* else, fall through */ case NE_Z_FINISHED: /* complete gzip response */ case NE_Z_PASSTHROUGH: /* complete uncompressed response */ return ctx->reader(ctx->userdata, buf, 0); default: /* invalid state: truncated response. */ break; } /* else: truncated response, fail. */ ne_set_error(ctx->session, "Compressed response was truncated"); return NE_ERROR; } switch (ctx->state) { case NE_Z_PASSTHROUGH: /* move along there. */ return ctx->reader(ctx->userdata, buf, len); case NE_Z_FINISHED: /* Could argue for tolerance, and ignoring trailing content; * but it could mean something more serious. */ if (len > 0) { ne_set_error(ctx->session, "Unexpected content received after compressed stream"); return NE_ERROR; } break; case NE_Z_BEFORE_DATA: /* work out whether this is a compressed response or not. */ hdr = ne_get_response_header(ctx->request, "Content-Encoding"); if (hdr && strcasecmp(hdr, "gzip") == 0) { int ret; NE_DEBUG(NE_DBG_HTTP, "compress: got gzipped stream.\n"); /* inflateInit2() works here where inflateInit() doesn't. */ ret = inflateInit2(&ctx->zstr, -MAX_WBITS); if (ret != Z_OK) { set_zlib_error(ctx, _("Could not initialize zlib"), ret); return -1; } ctx->zstrinit = 1; } else { /* No Content-Encoding header: pass it on. TODO: we could * hack it and register the real callback now. But that * would require add_resp_body_rdr to have defined * ordering semantics etc etc */ ctx->state = NE_Z_PASSTHROUGH; return ctx->reader(ctx->userdata, buf, len); } ctx->state = NE_Z_IN_HEADER; /* FALLTHROUGH */ case NE_Z_IN_HEADER: /* copy as many bytes as possible into the buffer. */ if (len + ctx->hdrcount > 10) { count = 10 - ctx->hdrcount; } else { count = len; } memcpy(ctx->header + ctx->hdrcount, buf, count); ctx->hdrcount += count; /* have we got the full header yet? */ if (ctx->hdrcount != 10) { return 0; } buf += count; len -= count; switch (parse_header(ctx)) { case HDR_EXTENDED: if (len == 0) return 0; break; case HDR_ERROR: return NE_ERROR; case HDR_DONE: if (len > 0) { return do_inflate(ctx, buf, len); } break; } /* FALLTHROUGH */ case NE_Z_POST_HEADER: /* eating the filename string. */ zbuf = memchr(buf, '\0', len); if (zbuf == NULL) { /* not found it yet. */ return 0; } NE_DEBUG(NE_DBG_HTTP, "compresss: skipped %" NE_FMT_SIZE_T " header bytes.\n", zbuf - buf); /* found end of string. */ len -= (1 + zbuf - buf); buf = zbuf + 1; ctx->state = NE_Z_INFLATING; if (len == 0) { /* end of string was at end of buffer. */ return 0; } /* FALLTHROUGH */ case NE_Z_INFLATING: return do_inflate(ctx, buf, len); case NE_Z_AFTER_DATA: return process_footer(ctx, (unsigned char *)buf, len); } return 0; }
/* * This hook is called for with the response of a request. Here its checked * if a Set-Cookie header is there for the PHPSESSID. The key is stored into * the webdav session to be added to subsequent requests. */ static void post_request_hook(ne_request *req, void *userdata, const ne_status *status) { const char *set_cookie_header = NULL; const char *sc = NULL; char *key = NULL; (void) userdata; if (dav_session.session_key) return; /* We already have a session cookie, and we should ignore other ones */ if(!(status && req)) return; if( status->klass == 2 || status->code == 401 ) { /* successful request */ set_cookie_header = ne_get_response_header( req, "Set-Cookie" ); if( set_cookie_header ) { DEBUG_WEBDAV(" Set-Cookie found: %s", set_cookie_header); /* try to find a ', ' sequence which is the separator of neon if multiple Set-Cookie * headers are there. * The following code parses a string like this: * Set-Cookie: 50ace6bd8a669=p537brtt048jh8srlp2tuep7em95nh9u98mj992fbqc47d1aecp1; */ sc = set_cookie_header; while(sc) { const char *sc_val = sc; const char *sc_end = sc_val; int cnt = 0; int len = strlen(sc_val); /* The length of the rest of the header string. */ while( cnt < len && *sc_end != ';' && *sc_end != ',') { cnt++; sc_end++; } if( cnt == len ) { /* exit: We are at the end. */ sc = NULL; } else if( *sc_end == ';' ) { /* We are at the end of the session key. */ int keylen = sc_end-sc_val; if( key ) { int oldlen = strlen(key); key = c_realloc(key, oldlen + 2 + keylen+1); strcpy(key + oldlen, "; "); strncpy(key + oldlen + 2, sc_val, keylen); key[oldlen + 2 + keylen] = '\0'; } else { key = c_malloc(keylen+1); strncpy( key, sc_val, keylen ); key[keylen] = '\0'; } /* now search for a ',' to find a potential other header entry */ while(cnt < len && *sc_end != ',') { cnt++; sc_end++; } if( cnt < len ) sc = sc_end+2; /* mind the space after the comma */ else sc = NULL; } else if( *sc_end == ',' ) { /* A new entry is to check. */ if( *(sc_end + 1) == ' ') { sc = sc_end+2; } else { /* error condition */ sc = NULL; } } } } } else { DEBUG_WEBDAV("Request failed, don't take session header."); } if( key ) { DEBUG_WEBDAV("----> Session-key: %s", key); SAFE_FREE(dav_session.session_key); dav_session.session_key = key; } }
/* * fetches a resource list from the WebDAV server. This is equivalent to list dir. */ static struct listdir_context *fetch_resource_list(const char *uri, int depth) { struct listdir_context *fetchCtx; int ret = 0; ne_propfind_handler *hdl = NULL; ne_request *request = NULL; const char *content_type = NULL; char *curi = NULL; const ne_status *req_status = NULL; curi = _cleanPath( uri ); /* The old legacy one-level PROPFIND cache. Also gets filled by the recursive cache if 'infinity' did not suceed. */ if (propfind_cache) { if (c_streq(curi, propfind_cache->target)) { DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi); propfind_cache->ref++; SAFE_FREE(curi); return propfind_cache; } } fetchCtx = c_malloc( sizeof( struct listdir_context )); if (!fetchCtx) { errno = ENOMEM; SAFE_FREE(curi); return NULL; } fetchCtx->list = NULL; fetchCtx->target = curi; fetchCtx->currResource = NULL; fetchCtx->ref = 1; /* do a propfind request and parse the results in the results function, set as callback */ hdl = ne_propfind_create(dav_session.ctx, curi, depth); if(hdl) { ret = ne_propfind_named(hdl, ls_props, results, fetchCtx); request = ne_propfind_get_request( hdl ); req_status = ne_get_status( request ); } if( ret == NE_OK ) { fetchCtx->currResource = fetchCtx->list; /* Check the request status. */ if( req_status && req_status->klass != 2 ) { set_errno_from_http_errcode(req_status->code); DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code, req_status->reason_phrase); ret = NE_CONNECT; set_error_message(req_status->reason_phrase); oc_notify_progress( uri, CSYNC_NOTIFY_ERROR, req_status->code, (intptr_t)(req_status->reason_phrase) ); } DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code); } else { if( ret == NE_ERROR && req_status->code == 404) { errno = ENOENT; } else { set_errno_from_neon_errcode(ret); } } if( ret == NE_OK ) { /* Check the content type. If the server has a problem, ie. database is gone or such, * the content type is not xml but a html error message. Stop on processing if it's * not XML. * FIXME: Generate user error message from the reply content. */ content_type = ne_get_response_header( request, "Content-Type" ); if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) { DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.", content_type ? content_type: "<empty>"); errno = ERRNO_WRONG_CONTENT; set_error_message("Server error: PROPFIND reply is not XML formatted!"); ret = NE_CONNECT; } } if( ret != NE_OK ) { const char *err = NULL; set_errno_from_neon_errcode(ret); err = ne_get_error( dav_session.ctx ); if(err) { set_error_message(err); } DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>"); } if( hdl ) ne_propfind_destroy(hdl); if( ret != NE_OK ) { free_fetchCtx(fetchCtx); return NULL; } free_fetchCtx(propfind_cache); propfind_cache = fetchCtx; propfind_cache->ref++; return fetchCtx; }
static int fetch_resource_list( const char *uri, int depth, struct listdir_context *fetchCtx ) { int ret = 0; ne_propfind_handler *hdl = NULL; ne_request *request = NULL; const char *content_type = NULL; char *curi = NULL; const ne_status *req_status = NULL; curi = _cleanPath( uri ); if (!fetchCtx) { errno = ENOMEM; SAFE_FREE(curi); return -1; } fetchCtx->list = NULL; fetchCtx->target = curi; fetchCtx->currResource = NULL; /* do a propfind request and parse the results in the results function, set as callback */ hdl = ne_propfind_create(dav_session.ctx, curi, depth); if(hdl) { ret = ne_propfind_named(hdl, ls_props, results, fetchCtx); request = ne_propfind_get_request( hdl ); req_status = ne_get_status( request ); } if( ret == NE_OK ) { fetchCtx->currResource = fetchCtx->list; /* Check the request status. */ if( req_status && req_status->klass != 2 ) { set_errno_from_http_errcode(req_status->code); DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code, req_status->reason_phrase); ret = NE_CONNECT; set_error_message(req_status->reason_phrase); } DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1); } else { if( ret == NE_ERROR && req_status->code == 404) { errno = ENOENT; } else { set_errno_from_neon_errcode(ret); } } if( ret == NE_OK ) { /* Check the content type. If the server has a problem, ie. database is gone or such, * the content type is not xml but a html error message. Stop on processing if it's * not XML. * FIXME: Generate user error message from the reply content. */ content_type = ne_get_response_header( request, "Content-Type" ); if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) { DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.", content_type ? content_type: "<empty>"); errno = ERRNO_WRONG_CONTENT; set_error_message("Server error: PROPFIND reply is not XML formatted!"); ret = NE_CONNECT; } } #ifndef NDEBUG if( ret != NE_OK ) { const char *err = ne_get_error(dav_session.ctx); DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>"); } #endif /* NDEBUG */ if (hdl != NULL) { ne_propfind_destroy(hdl); } #ifndef NDEBUG if (ret == NE_REDIRECT) { const ne_uri *redir_ne_uri = ne_redirect_location(dav_session.ctx); if (redir_ne_uri) { char *redir_uri = ne_uri_unparse(redir_ne_uri); DEBUG_WEBDAV("Permanently moved to %s", redir_uri); } } #endif /* NDEBUG */ if( ret != NE_OK ) { free_fetchCtx(fetchCtx); return -1; } return 0; }
void fetch_resource_list_recursive(const char *uri, const char *curi) { int ret = 0; ne_propfind_handler *hdl = NULL; ne_request *request = NULL; const char *content_type = NULL; const ne_status *req_status = NULL; int depth = NE_DEPTH_INFINITE; DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi); /* do a propfind request and parse the results in the results function, set as callback */ hdl = ne_propfind_create(dav_session.ctx, curi, depth); if(hdl) { ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi); request = ne_propfind_get_request( hdl ); req_status = ne_get_status( request ); } if( ret == NE_OK ) { /* Check the request status. */ if( req_status && req_status->klass != 2 ) { set_errno_from_http_errcode(req_status->code); DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code, req_status->reason_phrase); ret = NE_CONNECT; set_error_message(req_status->reason_phrase); } DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0); } else { if( ret == NE_ERROR && req_status->code == 404) { errno = ENOENT; } else { set_errno_from_neon_errcode(ret); } } if( ret == NE_OK ) { /* Check the content type. If the server has a problem, ie. database is gone or such, * the content type is not xml but a html error message. Stop on processing if it's * not XML. * FIXME: Generate user error message from the reply content. */ content_type = ne_get_response_header( request, "Content-Type" ); if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) { DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.", content_type ? content_type: "<empty>"); errno = ERRNO_WRONG_CONTENT; set_error_message("Server error: PROPFIND reply is not XML formatted!"); ret = NE_CONNECT; } } if( ret != NE_OK ) { const char *err = NULL; err = ne_get_error( dav_session.ctx ); DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>"); } if( hdl ) ne_propfind_destroy(hdl); if( ret != NE_OK ) { return; } return; }
static const char* owncloud_get_etag( const char *path ) { ne_request *req = NULL; const char *header = NULL; char *uri = _cleanPath(path); char *cbuf = NULL; csync_vio_file_stat_t *fs = NULL; bool doHeadRequest = false; if (_id_cache.uri && c_streq(path, _id_cache.uri)) { header = _id_cache.id; } doHeadRequest= false; /* ownCloud server doesn't have good support for HEAD yet */ if( !header && doHeadRequest ) { int neon_stat; /* Perform an HEAD request to the resource. HEAD delivers the * ETag header back. */ req = ne_request_create(dav_session.ctx, "HEAD", uri); neon_stat = ne_request_dispatch(req); set_errno_from_neon_errcode( neon_stat ); header = ne_get_response_header(req, "etag"); } /* If the request went wrong or the server did not respond correctly * (that can happen for collections) a stat call is done which translates * into a PROPFIND request. */ if( ! header ) { /* ... and do a stat call. */ fs = csync_vio_file_stat_new(); if(fs == NULL) { DEBUG_WEBDAV( "owncloud_get_etag: memory fault."); errno = ENOMEM; return NULL; } if( owncloud_stat( path, fs ) == 0 ) { header = fs->etag; } } /* In case the result is surrounded by "" cut them away. */ if( header ) { cbuf = csync_normalize_etag(header); } /* fix server problem: If we end up with an empty string, set something strange... */ if( c_streq(cbuf, "") || c_streq(cbuf, "\"\"") ) { SAFE_FREE(cbuf); cbuf = c_strdup("empty_etag"); } DEBUG_WEBDAV("Get file ID for %s: %s", path, cbuf ? cbuf:"<null>"); if( fs ) csync_vio_file_stat_destroy(fs); if( req ) ne_request_destroy(req); SAFE_FREE(uri); return cbuf; }
/* create a socket for connecting to remote server */ static gboolean gst_neonhttp_src_start (GstBaseSrc * bsrc) { GstNeonhttpSrc *src = GST_NEONHTTP_SRC (bsrc); const gchar *content_length; gint res; #ifndef GST_DISABLE_GST_DEBUG if (src->neon_http_debug) ne_debug_init (stderr, NE_DBG_HTTP); #endif ne_oom_callback (oom_callback); res = ne_sock_init (); if (res != 0) goto init_failed; res = gst_neonhttp_src_send_request_and_redirect (src, &src->session, &src->request, 0, src->automatic_redirect); if (res != NE_OK || !src->session) { if (res == HTTP_SOCKET_ERROR) { goto socket_error; } else if (res == HTTP_REQUEST_WRONG_PROXY) { goto wrong_proxy; } else { goto begin_req_failed; } } content_length = ne_get_response_header (src->request, "Content-Length"); if (content_length) src->content_size = g_ascii_strtoull (content_length, NULL, 10); else src->content_size = -1; if (TRUE) { /* Icecast stuff */ const gchar *str_value; GstTagList *tags; gchar *iradio_name; gchar *iradio_url; gchar *iradio_genre; gint icy_metaint; tags = gst_tag_list_new_empty (); str_value = ne_get_response_header (src->request, "icy-metaint"); if (str_value) { if (sscanf (str_value, "%d", &icy_metaint) == 1) { GstCaps *icy_caps; icy_caps = gst_caps_new_simple ("application/x-icy", "metadata-interval", G_TYPE_INT, icy_metaint, NULL); gst_base_src_set_caps (GST_BASE_SRC (src), icy_caps); } } /* FIXME: send tags with name, genre, url */ str_value = ne_get_response_header (src->request, "icy-name"); if (str_value) { iradio_name = gst_neonhttp_src_unicodify (str_value); if (iradio_name) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, iradio_name, NULL); g_free (iradio_name); } } str_value = ne_get_response_header (src->request, "icy-genre"); if (str_value) { iradio_genre = gst_neonhttp_src_unicodify (str_value); if (iradio_genre) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, iradio_genre, NULL); g_free (iradio_genre); } } str_value = ne_get_response_header (src->request, "icy-url"); if (str_value) { iradio_url = gst_neonhttp_src_unicodify (str_value); if (iradio_url) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, iradio_url, NULL); g_free (iradio_url); } } if (!gst_tag_list_is_empty (tags)) { GST_DEBUG_OBJECT (src, "pushing tag list %" GST_PTR_FORMAT, tags); gst_pad_push_event (GST_BASE_SRC_PAD (src), gst_event_new_tag (tags)); } else { gst_tag_list_unref (tags); } } return TRUE; /* ERRORS */ init_failed: { GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), ("ne_sock_init() failed: %d", res)); return FALSE; } socket_error: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("HTTP Request failed when opening socket: %d", res)); return FALSE; } wrong_proxy: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Proxy Server URI is invalid - make sure that either both proxy host " "and port are specified or neither.")); return FALSE; } begin_req_failed: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Could not begin request: %d", res)); return FALSE; } }
/* 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; }