st-transfer.c
来自「linux下网络收音机的源码」· C语言 代码 · 共 1,115 行 · 第 1/2 页
C
1,115 行
/* * Copyright (c) 2002, 2003, 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <string.h>#include <stdlib.h>#include <curl/curl.h>#ifdef ST_REGRESSION_TEST#define _(String) (String)#define st_notice g_warning#else#include <glib/gi18n.h>#include <gtk/gtk.h>#include "sgtk-auth-dialog.h"#include "st-dialog-api.h"#include "st-settings.h"#include "st-thread.h"#include "st-util-api.h"#include "st-shell.h"#endif /* ST_REGRESSION_TEST */#include "sg-util.h"#include "st-transfer.h"#define AGENT_STRING "streamtuner"/* maintain compatibility with old libcurl versions */#ifndef CURLOPT_WRITEDATA#define CURLOPT_WRITEDATA CURLOPT_FILE#endif#ifndef CURLOPT_HEADERDATA#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER#endif/* * RFC 2616 3.7.1 says that if no charset is provided, media subtypes * of the "text" type are defined to have a default charset value of * "ISO-8859-1". */#define CHARSET(header, body) ((body) ? (body) : ((header) ? (header) : "ISO-8859-1"))/*** type definitions ********************************************************//* * libcurl already provides this prototype as curl_write_callback, but * we are not gonna rely on it as it's undocumented */typedef size_t (CurlCallback) (const char *buffer, size_t size, size_t nitems, gpointer data);typedef struct{#ifndef ST_REGRESSION_TEST STThread *thread;#endif double downloaded; const char *url; STTransferFlags flags; STTransferSession *session; char error[CURL_ERROR_SIZE]; CurlCallback *header_cb; gpointer header_data; CurlCallback *body_cb; gpointer body_data; curl_proxytype proxy_type; char *proxy_server; int proxy_port; char *proxy_userpwd; char *header_charset; char *body_charset;} STTransfer;struct _STTransferSession{ CURL *handle;};typedef enum{ ST_TRANSFER_SECTION_HEADERS, ST_TRANSFER_SECTION_BODY} STTransferSection;typedef struct{ STTransfer *transfer; STTransferSection section; GString *line; char terminator[2]; /* \n\0, \r\n or \r\0 */ STTransferLineCallback line_cb; gpointer line_cb_data;} STTransferLineData;/*** function declarations ***************************************************/static gboolean st_transfer_perform (STTransfer *transfer, GError **err);static gboolean st_transfer_set_proxy_settings (STTransfer *transfer);static void st_transfer_free_proxy_settings (STTransfer *transfer);#ifndef ST_REGRESSION_TESTstatic char *st_transfer_get_hostname (const char *url);#endifstatic gboolean st_transfer_progress_cb (gpointer data, double dltotal, double dlnow, double ultotal, double ulnow);static gboolean st_transfer_session_get_internal (STTransferSession *session, const char *url, STTransferFlags flags, char **headers, char **body, GError **err);static char *st_transfer_get_header_charset (const char *header);static char *st_transfer_get_body_charset (const char *body);static void st_transfer_line_data_init (STTransferLineData *data, STTransfer *transfer, STTransferSection section, STTransferLineCallback cb, gpointer cb_data);static void st_transfer_line_data_flush (STTransferLineData *data);static void st_transfer_line_data_free (STTransferLineData *data, gboolean flush);static gboolean st_transfer_session_get_by_line_internal (STTransferSession *session, const char *url, STTransferFlags flags, STTransferLineCallback header_cb, gpointer header_data, STTransferLineCallback body_cb, gpointer body_data, GError **err);static size_t st_transfer_session_get_cb (const char *buffer, size_t size, size_t nitems, gpointer data);static size_t st_transfer_session_get_binary_cb (const char *buffer, size_t size, size_t nitems, gpointer data);static size_t st_transfer_session_get_by_line_cb (const char *buffer, size_t size, size_t nitems, gpointer data);/*** API implementation ******************************************************//** * st_transfer_session_new: * * Creates a new transfer session. * * Return value: the new session, which should be freed with * st_transfer_session_free() when no longer needed. **/STTransferSession *st_transfer_session_new (void){ STTransferSession *session; session = g_new(STTransferSession, 1); session->handle = curl_easy_init(); return session;}/** * st_transfer_session_free: * @session: the transfer session to destroy. * * Destroys @session. **/voidst_transfer_session_free (STTransferSession *session){ g_return_if_fail(session != NULL); curl_easy_cleanup(session->handle); g_free(session);}/* * Deprecated. */char *st_transfer_get_full (const char *url, GError **err){ STTransferSession *session; gboolean status; char *body; g_return_val_if_fail(url != NULL, FALSE); session = st_transfer_session_new(); status = st_transfer_session_get_internal(session, url, 0, NULL, &body, err); st_transfer_session_free(session); return status ? body : NULL;}/** * st_transfer_session_get: * @session: a transfer session. * @url: the URL of the data to get. * @flags: the transfer flags. Valid flags are #ST_TRANSFER_UTF8, * #ST_TRANSFER_PARSE_HTTP_CHARSET and * #ST_TRANSFER_PARSE_HTML_CHARSET. * @headers: a location to return the header data, or %NULL. The * returned data is guaranteed to be valid ASCII. * @body: a location to return the body data, or %NULL. If * #ST_TRANSFER_UTF8 is used, the returned data is guaranteed to be * valid UTF-8. * @err: a location to store errors, or %NULL. * * Gets the data located at @url. * * Return value: %FALSE if there was an error (in such case, @err will * be set). If %TRUE is returned, strings will be stored at @headers * and @body. They should be freed when no longer needed. **/gbooleanst_transfer_session_get (STTransferSession *session, const char *url, STTransferFlags flags, char **headers, char **body, GError **err){ gboolean status; g_return_val_if_fail(session != NULL, FALSE); g_return_val_if_fail(url != NULL, FALSE); g_return_val_if_fail((flags & ST_TRANSFER_PASS_NEWLINE) == 0, FALSE); status = st_transfer_session_get_internal(session, url, flags, headers, body, err); return status;}/** * st_transfer_session_get_binary: * @session: a transfer session. * @url: the URL of the data to get. * @flags: must be 0. * @headers: a location to return the header data, or %NULL. The * returned data is guaranteed to be valid ASCII. * @body: a location to return the body data, or %NULL. If set, * @body_len must also be set. * @body_len: a location to return the body length, or %NULL. * @err: a location to store errors, or %NULL. * * Gets the binary data located at @url. * * Return value: %FALSE if there was an error (in such case, @err will * be set). If %TRUE is returned, a string will be stored at @headers * and a character buffer will be stored at @body. They both should be * freed when no longer needed. **/gbooleanst_transfer_session_get_binary (STTransferSession *session, const char *url, STTransferFlags flags, char **headers, guint8 **body, unsigned int *body_len, GError **err){ STTransfer transfer = { 0, }; GString *header_string; GByteArray *body_array; gboolean status; g_return_val_if_fail(session != NULL, FALSE); g_return_val_if_fail(url != NULL, FALSE); g_return_val_if_fail((flags & ST_TRANSFER_PASS_NEWLINE) == 0, FALSE); g_return_val_if_fail((flags & ST_TRANSFER_UTF8) == 0, FALSE); g_return_val_if_fail((flags & ST_TRANSFER_PARSE_HTTP_CHARSET) == 0, FALSE); g_return_val_if_fail((flags & ST_TRANSFER_PARSE_HTML_CHARSET) == 0, FALSE); transfer.url = url; transfer.flags = flags; transfer.session = session; if (headers) { header_string = g_string_new(NULL); transfer.header_cb = st_transfer_session_get_cb; transfer.header_data = header_string; } if (body) { body_array = g_byte_array_new(); transfer.body_cb = st_transfer_session_get_binary_cb; transfer.body_data = body_array; } status = st_transfer_perform(&transfer, err); if (status) { if (headers) { if (sg_ascii_validate(header_string->str)) *headers = header_string->str; else { g_set_error(err, 0, 0, _("invalid ASCII in HTTP headers")); status = FALSE; } } if (body && status) { *body = body_array->data; *body_len = body_array->len; } } if (headers) g_string_free(header_string, ! status); if (body) g_byte_array_free(body_array, ! status); return status;}/* * Deprecated */char *st_transfer_get_full_with_session (STTransferSession *session, const char *url, GError **err){ gboolean status; char *body; g_return_val_if_fail(session != NULL, FALSE); g_return_val_if_fail(url != NULL, FALSE); status = st_transfer_session_get_internal(session, url, 0, NULL, &body, err); return status ? body : NULL;}static gbooleanst_transfer_session_get_internal (STTransferSession *session, const char *url, STTransferFlags flags, char **headers, char **body, GError **err){ STTransfer transfer = { 0, }; GString *header_string = NULL; GString *body_string; gboolean status; g_return_val_if_fail(session != NULL, FALSE); g_return_val_if_fail(url != NULL, FALSE); transfer.url = url; transfer.flags = flags; transfer.session = session; if (headers || flags & (ST_TRANSFER_UTF8 | ST_TRANSFER_PARSE_HTTP_CHARSET)) { header_string = g_string_new(NULL); transfer.header_cb = st_transfer_session_get_cb; transfer.header_data = header_string; } if (body) { body_string = g_string_new(NULL); transfer.body_cb = st_transfer_session_get_cb; transfer.body_data = body_string; } status = st_transfer_perform(&transfer, err); if (status) { if (header_string && ! sg_ascii_validate(header_string->str)) { g_set_error(err, 0, 0, _("invalid ASCII in HTTP headers")); status = FALSE; } if (status && flags & ST_TRANSFER_UTF8) { char *header_charset = NULL; if (flags & ST_TRANSFER_PARSE_HTTP_CHARSET) { char **lines; int i; lines = g_strsplit(header_string->str, "\r\n", 0); for (i = 0; lines[i] && ! header_charset; i++) header_charset = st_transfer_get_header_charset(lines[i]); g_strfreev(lines); } if (body) { char *body_charset; char *converted; body_charset = flags & ST_TRANSFER_PARSE_HTML_CHARSET ? st_transfer_get_body_charset(body_string->str) : NULL; converted = g_convert(body_string->str, body_string->len, "UTF-8", CHARSET(header_charset, body_charset), NULL, NULL, err); if (converted) { g_string_assign(body_string, converted); g_free(converted); } else status = FALSE; g_free(body_charset); } g_free(header_charset); } if (status) { if (headers) *headers = header_string->str; if (body) *body = body_string->str; } } if (header_string) g_string_free(header_string, ! (headers && status)); if (body) g_string_free(body_string, ! status); return status;}/* * Deprecated. */gbooleanst_transfer_get_lines (const char *url, STTransferLineCallback cb, gpointer data, GError **err){ STTransferSession *session; gboolean status; g_return_val_if_fail(url != NULL, FALSE); g_return_val_if_fail(cb != NULL, FALSE); session = st_transfer_session_new(); status = st_transfer_session_get_by_line_internal(session, url, 0, NULL, NULL, cb, data, err); st_transfer_session_free(session); return status;}/** * st_transfer_session_get_by_line: * @session: a transfer session. * @url: the URL of the data to get. * @flags: the transfer flags. Valid flags are * #ST_TRANSFER_PASS_NEWLINE, #ST_TRANSFER_UTF8, * #ST_TRANSFER_PARSE_HTTP_CHARSET and * #ST_TRANSFER_PARSE_HTML_CHARSET. * @header_cb: a function to call when a header line arrives, or * %NULL. The line passed to the function is guaranteed to be valid * ASCII. * @header_data: data to pass to @header_cb. * @body_cb: a function to call when a body line arrives, or %NULL. If * #ST_TRANSFER_UTF8 is used, the line passed to the function is * guaranteed to be valid UTF-8. * @body_data: data to pass to @body_cb. * @err: a location to store errors, or %NULL. * * Gets the data located at @url, splitting it into lines and passing * them to @header_cb and @body_cb. * * Return value: %FALSE if there was an error (in such case, @err will * be set). **/gbooleanst_transfer_session_get_by_line (STTransferSession *session, const char *url, STTransferFlags flags, STTransferLineCallback header_cb, gpointer header_data, STTransferLineCallback body_cb, gpointer body_data, GError **err){ gboolean status; g_return_val_if_fail(session != NULL, FALSE); g_return_val_if_fail(url != NULL, FALSE); status = st_transfer_session_get_by_line_internal(session, url, flags, header_cb, header_data, body_cb, body_data, err); return status;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?