static char * thex_download_handle_xml(struct thex_download *ctx, const char *data, size_t size) { xnode_t *hashtree = NULL, *node; char *hashtree_id = NULL; bool success = FALSE; vxml_parser_t *vp; vxml_error_t e; if (size <= 0) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH XML record has no data"); } goto finish; } /* * Parse the XML record. */ vp = vxml_parser_make("THEX record", VXML_O_STRIP_BLANKS); vxml_parser_add_data(vp, data, size); e = vxml_parse_tree(vp, &hashtree); vxml_parser_free(vp); if (VXML_E_OK != e) { if (GNET_PROPERTY(tigertree_debug)) { g_warning("TTH cannot parse XML record: %s", vxml_strerror(e)); dump_hex(stderr, "XML record", data, size); } goto finish; } if (0 != strcmp("hashtree", xnode_element_name(hashtree))) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find root hashtree element"); } goto finish; } node = find_element_by_name(hashtree, "file"); if (node) { if (!verify_element(node, "size", filesize_to_string(ctx->filesize))) goto finish; if (!verify_element(node, "segmentsize", THEX_SEGMENT_SIZE)) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find hashtree/file element"); } goto finish; } node = find_element_by_name(hashtree, "digest"); if (node) { if (!verify_element(node, "algorithm", THEX_HASH_ALGO)) goto finish; if (!verify_element(node, "outputsize", THEX_HASH_SIZE)) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find hashtree/digest element"); } goto finish; } node = find_element_by_name(hashtree, "serializedtree"); if (node) { const char *value; int error; if (!verify_element(node, "type", THEX_TREE_TYPE)) goto finish; value = xnode_prop_get(node, "uri"); if (NULL == value) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find property \"uri\" of node \"%s\"", xnode_element_name(node)); } goto finish; } hashtree_id = h_strdup(value); value = xnode_prop_get(node, "depth"); if (NULL == value) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find property \"depth\" of node \"%s\"", xnode_element_name(node)); } goto finish; } ctx->depth = parse_uint16(value, NULL, 10, &error); error |= ctx->depth > tt_full_depth(ctx->filesize); if (error) { ctx->depth = 0; g_warning("TTH bad value for \"depth\" of node \"%s\": \"%s\"", xnode_element_name(node), value); } if (error) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) g_debug("TTH couldn't find hashtree/serializedtree element"); goto finish; } success = TRUE; finish: if (!success) HFREE_NULL(hashtree_id); xnode_tree_free_null(&hashtree); return hashtree_id; }
/** * Process the SOAP reply from the server. */ static void soap_process_reply(soap_rpc_t *sr) { const char *buf; vxml_parser_t *vp; vxml_error_t e; xnode_t *root = NULL; xnode_t *xn = NULL; const char *charset; soap_rpc_check(sr); if (sr->reply_len != 0 && (GNET_PROPERTY(soap_trace) & SOCK_TRACE_IN)) { g_debug("----Got SOAP HTTP reply data from %s:", sr->url); if (log_printable(LOG_STDERR)) { fwrite(sr->reply_data, sr->reply_len, 1, stderr); fputs("----End SOAP HTTP reply\n", stderr); } } if (GNET_PROPERTY(soap_debug) > 2) { g_debug("SOAP \"%s\" at \"%s\": processing reply (%lu byte%s) HTTP %d", sr->action, sr->url, (unsigned long) sr->reply_len, 1 == sr->reply_len ? "" : "s", sr->http_code); } /* * If we got a 2xx reply, we need to parse up to the <Body> element * and then pass up the remaining to the user for parsing specific * elemnts accordingly. * * Other reply codes indicate an error. On 4xx replies we may not * have any XML to parse. On 5xx replies, we should usually have * a <Fault> indication under the <Body>. * * The strategy used here is to parse the XML reply into a tree and then * analyse the tree, ignoring the HTTP status code which is redundant. */ buf = header_get(sr->header, "Content-Type"); if (NULL == buf) goto no_xml; /* * MIME type and subtypes are case-insensitive (see RFC 2616, section 3.7). */ if ( !http_field_starts_with(buf, SOAP_TEXT_REPLY, FALSE) && !http_field_starts_with(buf, SOAP_APPLICATION_REPLY, FALSE) ) { if (GNET_PROPERTY(soap_debug)) { g_debug("SOAP \"%s\" at \"%s\": got unexpected Content-Type: %s", sr->action, sr->url, buf); } goto no_xml; } /* * Extract charset if given. */ charset = http_parameter_get(buf, "charset"); /* * Parse the SOAP envelope. */ vp = vxml_parser_make(sr->action, VXML_O_STRIP_BLANKS); vxml_parser_add_data(vp, sr->reply_data, sr->reply_len); if (!vxml_parser_set_charset(vp, charset)) { g_warning("SOAP \"%s\" at \"%s\": ignoring unknown charset \"%s\"", sr->action, sr->url, charset); } e = vxml_parse_tree(vp, &root); vxml_parser_free(vp); if (e != VXML_E_OK) { if (GNET_PROPERTY(soap_debug)) { g_debug("SOAP \"%s\" at \"%s\": cannot parse XML reply: %s", sr->action, sr->url, vxml_strerror(e)); } goto bad_xml; } g_assert(root != NULL); /* * Make sure we got a SOAP reply. */ if (!xnode_is_element_named(root, SOAP_NAMESPACE, SOAP_X_ENVELOPE)) goto not_soap; /* * Look for the <SOAP:Body> element. */ for (xn = xnode_first_child(root); TRUE; xn = xnode_next_sibling(xn)) { if (NULL == xn || !xnode_within_namespace(xn, SOAP_NAMESPACE)) goto bad_soap; if (0 == strcmp(SOAP_X_BODY, xnode_element_name(xn))) break; } /* * Inspect the first child of the <SOAP:Body> element. * * If it's a <SOAP:Fault>, go process it and return an error. * If it's another SOAP tag, we have an unknown structure. * Otherwise it's the reply, for user code to handle. */ xn = xnode_first_child(xn); if (NULL == xn) goto bad_soap; if (xnode_is_element_named(xn, SOAP_NAMESPACE, SOAP_X_FAULT)) { xnode_detach(xn); soap_fault(sr, xn); } else if (xnode_within_namespace(xn, SOAP_NAMESPACE)) { goto bad_soap; } else { xnode_detach(xn); soap_reply(sr, xn); } xnode_tree_free(root); return; not_soap: if (GNET_PROPERTY(soap_debug)) { g_debug("SOAP \"%s\" at \"%s\": unexpected root XML " "element <%s:%s>", sr->action, sr->url, EMPTY_STRING(xnode_element_ns(root)), xnode_element_name(root)); } xnode_tree_free(root); /* FALL THROUGH */ no_xml: soap_error(sr, SOAP_E_PROTOCOL); return; bad_soap: if (GNET_PROPERTY(soap_debug)) { g_debug("SOAP \"%s\" at \"%s\": unexpected XML structure", sr->action, sr->url); } if (GNET_PROPERTY(soap_debug) > 1) { g_debug("SOAP current node is %s", xnode_to_string(xn)); } if (GNET_PROPERTY(soap_debug) > 2) xfmt_tree_dump(root, stderr); xnode_tree_free(root); /* FALL THROUGH */ bad_xml: soap_error(sr, SOAP_E_PROCESSING); return; }