/** * Redefine callback invoked when we got the whole HTTP reply. * * @param ha the HTTP async request descriptor * @param s the socket on which we got the reply * @param status the first HTTP status line * @param header the parsed header structure */ static void gwc_got_reply(const http_async_t *ha, const gnutella_socket_t *s, const char *status, const header_t *header) { if (GNET_PROPERTY(bootstrap_debug) > 3) g_debug("GWC got reply from %s", http_async_url(ha)); if (GNET_PROPERTY(bootstrap_debug) > 5) { g_debug("----Got GWC reply from %s:", host_addr_to_string(s->addr)); if (log_printable(LOG_STDERR)) { fprintf(stderr, "%s\n", status); header_dump(stderr, header, "----"); } } }
/** * Redefine callback invoked when we got the whole HTTP reply. */ static void soap_got_reply(const http_async_t *ha, const struct gnutella_socket *s, const char *status, const header_t *header) { soap_rpc_t *sr = http_async_get_opaque(ha); soap_rpc_check(sr); if (GNET_PROPERTY(soap_trace) & SOCK_TRACE_IN) { g_debug("----Got SOAP HTTP reply from %s:", host_addr_to_string(s->addr)); if (log_printable(LOG_STDERR)) { fprintf(stderr, "%s\n", status); header_dump(stderr, header, "----"); } } }
/** * 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; }