comparison src/util.c @ 12887:4229503f1cd9

[gaim-migrate @ 15240] Added gaim_url_fetch_request(), which is an enhancement to the gaim_url_fetch() functionality that allows you to specify the request that gets submitted to the server and whether or not the headers are also returned. I'm going to use this for the UPnP stuff (watch this space). Also fixed a tyop in the xmlnode docs. Remove the status documentation from the API Changelog. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Sun, 15 Jan 2006 22:58:52 +0000
parents bad785371fa5
children 5e338dda872f
comparison
equal deleted inserted replaced
12886:d8e8feac6cce 12887:4229503f1cd9
46 46
47 char *url; 47 char *url;
48 gboolean full; 48 gboolean full;
49 char *user_agent; 49 char *user_agent;
50 gboolean http11; 50 gboolean http11;
51 char *request;
52 gboolean include_headers;
51 53
52 int inpa; 54 int inpa;
53 55
54 gboolean sentreq; 56 gboolean sentreq;
55 gboolean startsaving; 57 gboolean startsaving;
2858 } 2860 }
2859 2861
2860 static void 2862 static void
2861 destroy_fetch_url_data(GaimFetchUrlData *gfud) 2863 destroy_fetch_url_data(GaimFetchUrlData *gfud)
2862 { 2864 {
2863 if (gfud->webdata != NULL) g_free(gfud->webdata); 2865 g_free(gfud->webdata);
2864 if (gfud->url != NULL) g_free(gfud->url); 2866 g_free(gfud->url);
2865 if (gfud->user_agent != NULL) g_free(gfud->user_agent); 2867 g_free(gfud->user_agent);
2866 if (gfud->website.address != NULL) g_free(gfud->website.address); 2868 g_free(gfud->website.address);
2867 if (gfud->website.page != NULL) g_free(gfud->website.page); 2869 g_free(gfud->website.page);
2868 if (gfud->website.user != NULL) g_free(gfud->website.user); 2870 g_free(gfud->website.user);
2869 if (gfud->website.passwd != NULL) g_free(gfud->website.passwd); 2871 g_free(gfud->website.passwd);
2872 g_free(gfud->request);
2870 2873
2871 g_free(gfud); 2874 g_free(gfud);
2872 } 2875 }
2873 2876
2874 static gboolean 2877 static gboolean
2918 close(sock); 2921 close(sock);
2919 2922
2920 gaim_debug_info("gaim_url_fetch", "Redirecting to %s\n", new_url); 2923 gaim_debug_info("gaim_url_fetch", "Redirecting to %s\n", new_url);
2921 2924
2922 /* Try again, with this new location. */ 2925 /* Try again, with this new location. */
2923 gaim_url_fetch(new_url, full, gfud->user_agent, gfud->http11, 2926 gaim_url_fetch_request(new_url, full, gfud->user_agent,
2924 gfud->callback, gfud->user_data); 2927 gfud->http11, gfud->request, gfud->include_headers,
2928 gfud->callback, gfud->user_data);
2925 2929
2926 /* Free up. */ 2930 /* Free up. */
2927 g_free(new_url); 2931 g_free(new_url);
2928 destroy_fetch_url_data(gfud); 2932 destroy_fetch_url_data(gfud);
2929 2933
2942 /* This is still technically wrong, since headers are case-insensitive 2946 /* This is still technically wrong, since headers are case-insensitive
2943 * [RFC 2616, section 4.2], though this ought to catch the normal case. 2947 * [RFC 2616, section 4.2], though this ought to catch the normal case.
2944 * Note: data is _not_ nul-terminated. 2948 * Note: data is _not_ nul-terminated.
2945 */ 2949 */
2946 if (data_len > 16) { 2950 if (data_len > 16) {
2947 p = strncmp(data, "Content-Length: ", 16) == 0? data: NULL; 2951 p = strncmp(data, "Content-Length: ", 16) == 0 ? data : NULL;
2948 if (!p) { 2952 if (!p) {
2949 p = g_strstr_len(data, data_len, "\nContent-Length: "); 2953 p = g_strstr_len(data, data_len, "\nContent-Length: ");
2950 if (p) 2954 if (p)
2951 p += 1; 2955 p += 1;
2952 } 2956 }
2957 if (!p)
2958 p = (strncmp(data, "CONTENT-LENGTH: ", 16) == 0)
2959 ? data : NULL;
2960 if (!p) {
2961 p = g_strstr_len(data, data_len, "\nContent-Length: ");
2962 if (p)
2963 p++;
2964 }
2965 if (!p) {
2966 p = g_strstr_len(data, data_len, "\nCONTENT-LENGTH: ");
2967 if (p)
2968 p++;
2969 }
2970
2971 if (p)
2972 p += 16;
2953 } 2973 }
2954 2974
2955 /* If we can find a Content-Length header at all, try to sscanf it. 2975 /* If we can find a Content-Length header at all, try to sscanf it.
2956 * Response headers should end with at least \r\n, so sscanf is safe, 2976 * Response headers should end with at least \r\n, so sscanf is safe,
2957 * if we make sure that there is indeed a \n in our header. 2977 * if we make sure that there is indeed a \n in our header.
2958 */ 2978 */
2959 if (p && g_strstr_len(p, data_len - (p - data), "\n")) { 2979 if (p && g_strstr_len(p, data_len - (p - data), "\n")) {
2960 sscanf(p, "Content-Length: %" G_GSIZE_FORMAT, &content_len); 2980 sscanf(p, "%" G_GSIZE_FORMAT, &content_len);
2961 gaim_debug_misc("parse_content_len", "parsed %u\n", content_len); 2981 gaim_debug_misc("parse_content_len", "parsed %u\n", content_len);
2962 } 2982 }
2963 2983
2964 return content_len; 2984 return content_len;
2965 } 2985 }
2982 return; 3002 return;
2983 } 3003 }
2984 3004
2985 if (!gfud->sentreq) 3005 if (!gfud->sentreq)
2986 { 3006 {
3007 char *send;
2987 char buf[1024]; 3008 char buf[1024];
2988 3009
2989 if (gfud->user_agent) 3010 if (gfud->request) {
2990 { 3011 send = gfud->request;
2991 /* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1 3012 } else {
2992 * clients must know how to handle the "chunked" transfer encoding. 3013 if (gfud->user_agent) {
2993 * Gaim doesn't know how to handle "chunked", so should always send 3014 /* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
2994 * the Host header regardless, to get around some observed problems 3015 * clients must know how to handle the "chunked" transfer encoding.
2995 */ 3016 * Gaim doesn't know how to handle "chunked", so should always send
2996 g_snprintf(buf, sizeof(buf), 3017 * the Host header regardless, to get around some observed problems
2997 "GET %s%s HTTP/%s\r\n" 3018 */
2998 "Connection: close\r\n" 3019 g_snprintf(buf, sizeof(buf),
2999 "User-Agent: %s\r\n" 3020 "GET %s%s HTTP/%s\r\n"
3000 "Host: %s\r\n\r\n", 3021 "Connection: close\r\n"
3001 (gfud->full ? "" : "/"), 3022 "User-Agent: %s\r\n"
3002 (gfud->full ? gfud->url : gfud->website.page), 3023 "Host: %s\r\n\r\n",
3003 (gfud->http11 ? "1.1" : "1.0"), 3024 (gfud->full ? "" : "/"),
3004 gfud->user_agent, gfud->website.address); 3025 (gfud->full ? gfud->url : gfud->website.page),
3005 } 3026 (gfud->http11 ? "1.1" : "1.0"),
3006 else 3027 gfud->user_agent, gfud->website.address);
3007 { 3028 } else {
3008 g_snprintf(buf, sizeof(buf), 3029 g_snprintf(buf, sizeof(buf),
3009 "GET %s%s HTTP/%s\r\n" 3030 "GET %s%s HTTP/%s\r\n"
3010 "Connection: close\r\n" 3031 "Connection: close\r\n"
3011 "Host: %s\r\n\r\n", 3032 "Host: %s\r\n\r\n",
3012 (gfud->full ? "" : "/"), 3033 (gfud->full ? "" : "/"),
3013 (gfud->full ? gfud->url : gfud->website.page), 3034 (gfud->full ? gfud->url : gfud->website.page),
3014 (gfud->http11 ? "1.1" : "1.0"), 3035 (gfud->http11 ? "1.1" : "1.0"),
3015 gfud->website.address); 3036 gfud->website.address);
3016 } 3037 }
3017 3038 send = buf;
3018 gaim_debug_misc("gaim_url_fetch", "Request: %s\n", buf); 3039 }
3019 3040
3020 write(sock, buf, strlen(buf)); 3041 gaim_debug_misc("gaim_url_fetch", "Request: %s\n", send);
3042
3043 write(sock, send, strlen(send));
3021 fcntl(sock, F_SETFL, O_NONBLOCK); 3044 fcntl(sock, F_SETFL, O_NONBLOCK);
3022 gfud->sentreq = TRUE; 3045 gfud->sentreq = TRUE;
3023 gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ, 3046 gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ,
3024 url_fetched_cb, url_data); 3047 url_fetched_cb, url_data);
3025 gfud->data_len = 4096; 3048 gfud->data_len = 4096;
3026 gfud->webdata = g_malloc(gfud->data_len); 3049 gfud->webdata = g_malloc(gfud->data_len);
3027 3050
3028 return; 3051 return;
3029 } 3052 }
3076 else 3099 else
3077 { 3100 {
3078 gfud->has_explicit_data_len = TRUE; 3101 gfud->has_explicit_data_len = TRUE;
3079 } 3102 }
3080 3103
3104 content_len = MAX(content_len, body_len);
3105
3106 /* If we're returning the headers too, we don't need to clean them out */
3107 if (gfud->include_headers) {
3108 gfud->data_len = content_len + header_len;
3109 return;
3110 }
3111
3081 if (gfud->len > (header_len + 1)) 3112 if (gfud->len > (header_len + 1))
3082 body_len = (gfud->len - header_len); 3113 body_len = (gfud->len - header_len);
3083 3114
3084 content_len = MAX(content_len, body_len);
3085 3115
3086 new_data = g_try_malloc(content_len); 3116 new_data = g_try_malloc(content_len);
3087 if (new_data == NULL) { 3117 if (new_data == NULL) {
3088 gaim_debug_error("gaim_url_fetch", "Failed to allocate %u bytes: %s\n", 3118 gaim_debug_error("gaim_url_fetch", "Failed to allocate %u bytes: %s\n",
3089 content_len, strerror(errno)); 3119 content_len, strerror(errno));
3149 destroy_fetch_url_data(gfud); 3179 destroy_fetch_url_data(gfud);
3150 } 3180 }
3151 } 3181 }
3152 3182
3153 void 3183 void
3154 gaim_url_fetch(const char *url, gboolean full, 3184 gaim_url_fetch_request(const char *url, gboolean full,
3155 const char *user_agent, gboolean http11, 3185 const char *user_agent, gboolean http11,
3156 void (*cb)(gpointer, const char *, size_t), 3186 const char *request, gboolean include_headers,
3157 void *user_data) 3187 GaimURLFetchCallback cb, void *user_data)
3158 { 3188 {
3159 GaimFetchUrlData *gfud; 3189 GaimFetchUrlData *gfud;
3160 3190
3161 g_return_if_fail(url != NULL); 3191 g_return_if_fail(url != NULL);
3162 g_return_if_fail(cb != NULL); 3192 g_return_if_fail(cb != NULL);
3165 "requested to fetch (%s), full=%d, user_agent=(%s), http11=%d\n", 3195 "requested to fetch (%s), full=%d, user_agent=(%s), http11=%d\n",
3166 url, full, user_agent?user_agent:"(null)", http11); 3196 url, full, user_agent?user_agent:"(null)", http11);
3167 3197
3168 gfud = g_new0(GaimFetchUrlData, 1); 3198 gfud = g_new0(GaimFetchUrlData, 1);
3169 3199
3170 gfud->callback = cb; 3200 gfud->callback = cb;
3171 gfud->user_data = user_data; 3201 gfud->user_data = user_data;
3172 gfud->url = g_strdup(url); 3202 gfud->url = g_strdup(url);
3173 gfud->user_agent = (user_agent != NULL ? g_strdup(user_agent) : NULL); 3203 gfud->user_agent = user_agent ? g_strdup(user_agent) : NULL;
3174 gfud->http11 = http11; 3204 gfud->http11 = http11;
3175 gfud->full = full; 3205 gfud->full = full;
3206 gfud->request = request ? g_strdup(request) : NULL;
3207 gfud->include_headers = include_headers;
3176 3208
3177 gaim_url_parse(url, &gfud->website.address, &gfud->website.port, 3209 gaim_url_parse(url, &gfud->website.address, &gfud->website.port,
3178 &gfud->website.page, &gfud->website.user, &gfud->website.passwd); 3210 &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
3179 3211
3180 if (gaim_proxy_connect(NULL, gfud->website.address, 3212 if (gaim_proxy_connect(NULL, gfud->website.address,