示例#1
0
/**
 * Find the status code and content type and inform the caller.
 *
 * Return true if the fetch is being aborted.
 */
static bool fetch_curl_process_headers(struct curl_fetch_info *f)
{
	long http_code;
	CURLcode code;
	fetch_msg msg;

	f->had_headers = true;

	if (!f->http_code) {
		code = curl_easy_getinfo(f->curl_handle, CURLINFO_HTTP_CODE,
					 &f->http_code);
		fetch_set_http_code(f->fetch_handle, f->http_code);
		assert(code == CURLE_OK);
	}
	http_code = f->http_code;
	LOG("HTTP status code %li", http_code);

	if (http_code == 304 && !f->post_urlenc && !f->post_multipart) {
		/* Not Modified && GET request */
		msg.type = FETCH_NOTMODIFIED;
		fetch_send_callback(&msg, f->fetch_handle);
		return true;
	}

	/* handle HTTP redirects (3xx response codes) */
	if (300 <= http_code && http_code < 400 && f->location != 0) {
		LOG("FETCH_REDIRECT, '%s'", f->location);
		msg.type = FETCH_REDIRECT;
		msg.data.redirect = f->location;
		fetch_send_callback(&msg, f->fetch_handle);
		return true;
	}

	/* handle HTTP 401 (Authentication errors) */
	if (http_code == 401) {
		msg.type = FETCH_AUTH;
		msg.data.auth.realm = f->realm;
		fetch_send_callback(&msg, f->fetch_handle);
		return true;
	}

	/* handle HTTP errors (non 2xx response codes) */
	if (f->only_2xx && strncmp(nsurl_access(f->url), "http", 4) == 0 &&
			(http_code < 200 || 299 < http_code)) {
		msg.type = FETCH_ERROR;
		msg.data.error = messages_get("Not2xx");
		fetch_send_callback(&msg, f->fetch_handle);
		return true;
	}

	if (f->abort)
		return true;

	return false;
}
示例#2
0
static void fetch_rsrc_send_callback(const fetch_msg *msg, 
		struct fetch_rsrc_context *c)
{
	c->locked = true;
	fetch_send_callback(msg, c->parent_fetch);
	c->locked = false;
}
示例#3
0
/** issue fetch callbacks with locking */
static inline bool fetch_javascript_send_callback(const fetch_msg *msg,
		struct fetch_javascript_context *ctx)
{
	ctx->locked = true;
	fetch_send_callback(msg, ctx->fetchh);
	ctx->locked = false;

	return ctx->aborted;
}
示例#4
0
static void ami_fetch_file_send_callback(fetch_msg msg,
		struct ami_file_fetch_info *fetch, const void *data,
		unsigned long size, fetch_error_code errorcode)
{
	fetch->locked = true;
	/* LOG(("ami file fetcher callback %ld",msg)); */
	fetch_send_callback(msg,fetch->fetch_handle,data,size,errorcode);
	fetch->locked = false;
}
示例#5
0
/**
 * Callback function for fetch progress.
 */
static int
fetch_curl_progress(void *clientp,
		    double dltotal,
		    double dlnow,
		    double ultotal,
		    double ulnow)
{
	static char fetch_progress_buffer[256]; /**< Progress buffer for cURL */
	struct curl_fetch_info *f = (struct curl_fetch_info *) clientp;
	uint64_t time_now_ms;
	fetch_msg msg;

	if (f->abort) {
		return 0;
        }

	msg.type = FETCH_PROGRESS;
	msg.data.progress = fetch_progress_buffer;

	/* Rate limit each fetch's progress notifications */
        nsu_getmonotonic_ms(&time_now_ms);
#define UPDATE_DELAY_MS (1000 / UPDATES_PER_SECOND)
	if (time_now_ms - f->last_progress_update < UPDATE_DELAY_MS) {
		return 0;
        }
#undef UPDATE_DELAY_MS
	f->last_progress_update = time_now_ms;

	if (dltotal > 0) {
		snprintf(fetch_progress_buffer, 255,
				messages_get("Progress"),
				human_friendly_bytesize(dlnow),
				human_friendly_bytesize(dltotal));
		fetch_send_callback(&msg, f->fetch_handle);
	} else {
		snprintf(fetch_progress_buffer, 255,
				messages_get("ProgressU"),
				human_friendly_bytesize(dlnow));
		fetch_send_callback(&msg, f->fetch_handle);
	}

	return 0;
}
示例#6
0
文件: curl.c 项目: EyMenZ/NetSurf-OS3
/**
 * Callback function for cURL.
 */
static size_t fetch_curl_data(char *data, size_t size, size_t nmemb, void *_f)
{
	struct curl_fetch_info *f = _f;
	CURLcode code;
	fetch_msg msg;

	/* ensure we only have to get this information once */
	if (!f->http_code)
	{
		code = curl_easy_getinfo(f->curl_handle, CURLINFO_HTTP_CODE,
					 &f->http_code);
		fetch_set_http_code(f->fetch_handle, f->http_code);
		assert(code == CURLE_OK);
	}

	/* ignore body if this is a 401 reply by skipping it and reset
	 * the HTTP response code to enable follow up fetches.
	 */
	if (f->http_code == 401)
	{
		f->http_code = 0;
		return size * nmemb;
	}

	if (f->abort || (!f->had_headers && fetch_curl_process_headers(f))) {
		f->stopped = true;
		return 0;
	}

	/* send data to the caller */
	msg.type = FETCH_DATA;
	msg.data.header_or_data.buf = (const uint8_t *) data;
	msg.data.header_or_data.len = size * nmemb;
	fetch_send_callback(&msg, f->fetch_handle);

	if (f->abort) {
		f->stopped = true;
		return 0;
	}

	return size * nmemb;
}
示例#7
0
/**
 * setup callback to allow the user to examine certificates which have
 * failed to validate during fetch.
 */
static void
curl_start_cert_validate(struct curl_fetch_info *f,
			 struct cert_info *certs)
{
	int depth;
	BIO *mem;
	BUF_MEM *buf;
	struct ssl_cert_info ssl_certs[MAX_CERTS];
	fetch_msg msg;

	for (depth = 0; depth <= f->cert_depth; depth++) {
		assert(certs[depth].cert != NULL);

		/* get certificate version */
		ssl_certs[depth].version = X509_get_version(certs[depth].cert);

		/* not before date */
		mem = BIO_new(BIO_s_mem());
		ASN1_TIME_print(mem, X509_get_notBefore(certs[depth].cert));
		BIO_get_mem_ptr(mem, &buf);
		(void) BIO_set_close(mem, BIO_NOCLOSE);
		BIO_free(mem);
		memcpy(ssl_certs[depth].not_before,
		       buf->data,
		       min(sizeof(ssl_certs[depth].not_before) - 1,
			   (unsigned)buf->length));
		ssl_certs[depth].not_before[min(sizeof(ssl_certs[depth].not_before) - 1,
					    (unsigned)buf->length)] = 0;
		BUF_MEM_free(buf);

		/* not after date */
		mem = BIO_new(BIO_s_mem());
		ASN1_TIME_print(mem,
				X509_get_notAfter(certs[depth].cert));
		BIO_get_mem_ptr(mem, &buf);
		(void) BIO_set_close(mem, BIO_NOCLOSE);
		BIO_free(mem);
		memcpy(ssl_certs[depth].not_after,
		       buf->data,
		       min(sizeof(ssl_certs[depth].not_after) - 1,
			   (unsigned)buf->length));
		ssl_certs[depth].not_after[min(sizeof(ssl_certs[depth].not_after) - 1,
					   (unsigned)buf->length)] = 0;
		BUF_MEM_free(buf);

		/* signature type */
		ssl_certs[depth].sig_type =
			X509_get_signature_type(certs[depth].cert);

		/* serial number */
		ssl_certs[depth].serial =
			ASN1_INTEGER_get(
				X509_get_serialNumber(certs[depth].cert));

		/* issuer name */
		mem = BIO_new(BIO_s_mem());
		X509_NAME_print_ex(mem,
				   X509_get_issuer_name(certs[depth].cert),
				   0, XN_FLAG_SEP_CPLUS_SPC |
				   XN_FLAG_DN_REV | XN_FLAG_FN_NONE);
		BIO_get_mem_ptr(mem, &buf);
		(void) BIO_set_close(mem, BIO_NOCLOSE);
		BIO_free(mem);
		memcpy(ssl_certs[depth].issuer,
		       buf->data,
		       min(sizeof(ssl_certs[depth].issuer) - 1,
			   (unsigned) buf->length));
		ssl_certs[depth].issuer[min(sizeof(ssl_certs[depth].issuer) - 1,
					(unsigned) buf->length)] = 0;
		BUF_MEM_free(buf);

		/* subject */
		mem = BIO_new(BIO_s_mem());
		X509_NAME_print_ex(mem,
				   X509_get_subject_name(certs[depth].cert),
				   0,
				   XN_FLAG_SEP_CPLUS_SPC |
				   XN_FLAG_DN_REV |
				   XN_FLAG_FN_NONE);
		BIO_get_mem_ptr(mem, &buf);
		(void) BIO_set_close(mem, BIO_NOCLOSE);
		BIO_free(mem);
		memcpy(ssl_certs[depth].subject,
		       buf->data,
		       min(sizeof(ssl_certs[depth].subject) - 1,
			   (unsigned)buf->length));
		ssl_certs[depth].subject[min(sizeof(ssl_certs[depth].subject) - 1,
					 (unsigned) buf->length)] = 0;
		BUF_MEM_free(buf);

		/* type of certificate */
		ssl_certs[depth].cert_type =
			X509_certificate_type(certs[depth].cert,
					      X509_get_pubkey(certs[depth].cert));

		/* and clean up */
		certs[depth].cert->references--;
		if (certs[depth].cert->references == 0) {
			X509_free(certs[depth].cert);
		}
	}

	msg.type = FETCH_CERT_ERR;
	msg.data.cert_err.certs = ssl_certs;
	msg.data.cert_err.num_certs = depth;
	fetch_send_callback(&msg, f->fetch_handle);
}
示例#8
0
/**
 * Callback function for headers.
 *
 * See RFC 2616 4.2.
 */
static size_t
fetch_curl_header(char *data, size_t size, size_t nmemb, void *_f)
{
	struct curl_fetch_info *f = _f;
	int i;
	fetch_msg msg;
	size *= nmemb;

	if (f->abort) {
		f->stopped = true;
		return 0;
	}

	msg.type = FETCH_HEADER;
	msg.data.header_or_data.buf = (const uint8_t *) data;
	msg.data.header_or_data.len = size;
	fetch_send_callback(&msg, f->fetch_handle);

#define SKIP_ST(o) for (i = (o); i < (int) size && (data[i] == ' ' || data[i] == '\t'); i++)

	if (12 < size && strncasecmp(data, "Location:", 9) == 0) {
		/* extract Location header */
		free(f->location);
		f->location = malloc(size);
		if (!f->location) {
			LOG("malloc failed");
			return size;
		}
		SKIP_ST(9);
		strncpy(f->location, data + i, size - i);
		f->location[size - i] = '\0';
		for (i = size - i - 1; i >= 0 &&
				(f->location[i] == ' ' ||
				f->location[i] == '\t' ||
				f->location[i] == '\r' ||
				f->location[i] == '\n'); i--)
			f->location[i] = '\0';
	} else if (15 < size && strncasecmp(data, "Content-Length:", 15) == 0) {
		/* extract Content-Length header */
		SKIP_ST(15);
		if (i < (int)size && '0' <= data[i] && data[i] <= '9')
			f->content_length = atol(data + i);
	} else if (17 < size && strncasecmp(data, "WWW-Authenticate:", 17) == 0) {
		/* extract the first Realm from WWW-Authenticate header */
		SKIP_ST(17);

		while (i < (int) size - 5 &&
				strncasecmp(data + i, "realm", 5))
			i++;
		while (i < (int) size - 1 && data[++i] != '"')
			/* */;
		i++;

		if (i < (int) size) {
			size_t end = i;

			while (end < size && data[end] != '"')
				++end;

			if (end < size) {
				free(f->realm);
				f->realm = malloc(end - i + 1);
				if (f->realm != NULL) {
					strncpy(f->realm, data + i, end - i);
					f->realm[end - i] = '\0';
				}
			}
		}
	} else if (11 < size && strncasecmp(data, "Set-Cookie:", 11) == 0) {
		/* extract Set-Cookie header */
		SKIP_ST(11);

		fetch_set_cookie(f->fetch_handle, &data[i]);
	}

	return size;
#undef SKIP_ST
}
示例#9
0
/**
 * Handle a completed fetch (CURLMSG_DONE from curl_multi_info_read()).
 *
 * \param curl_handle curl easy handle of fetch
 * \param result The result code of the completed fetch.
 */
static void fetch_curl_done(CURL *curl_handle, CURLcode result)
{
	bool finished = false;
	bool error = false;
	bool cert = false;
	bool abort_fetch;
	struct curl_fetch_info *f;
	char **_hideous_hack = (char **) (void *) &f;
	CURLcode code;
	struct cert_info certs[MAX_CERTS];

	/* find the structure associated with this fetch */
	/* For some reason, cURL thinks CURLINFO_PRIVATE should be a string?! */
	code = curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, _hideous_hack);
	assert(code == CURLE_OK);

	abort_fetch = f->abort;
	LOG("done %s", nsurl_access(f->url));

	if ((abort_fetch == false) &&
	    (result == CURLE_OK ||
	     ((result == CURLE_WRITE_ERROR) && (f->stopped == false)))) {
		/* fetch completed normally or the server fed us a junk gzip
		 * stream (usually in the form of garbage at the end of the
		 * stream). Curl will have fed us all but the last chunk of
		 * decoded data, which is sad as, if we'd received the last
		 * chunk, too, we'd be able to render the whole object.
		 * As is, we'll just have to accept that the end of the
		 * object will be truncated in this case and leave it to
		 * the content handlers to cope.
		 */
		if (f->stopped ||
		    (!f->had_headers &&	fetch_curl_process_headers(f))) {
			; /* redirect with no body or similar */
		} else {
			finished = true;
		}
	} else if (result == CURLE_PARTIAL_FILE) {
		/* CURLE_PARTIAL_FILE occurs if the received body of a
		 * response is smaller than that specified in the
		 * Content-Length header.
		 */
		if (!f->had_headers && fetch_curl_process_headers(f))
			; /* redirect with partial body, or similar */
		else {
			finished = true;
		}
	} else if (result == CURLE_WRITE_ERROR && f->stopped) {
		/* CURLE_WRITE_ERROR occurs when fetch_curl_data
		 * returns 0, which we use to abort intentionally
		 */
		;
	} else if (result == CURLE_SSL_PEER_CERTIFICATE ||
			result == CURLE_SSL_CACERT) {
		/* CURLE_SSL_PEER_CERTIFICATE renamed to
		 * CURLE_PEER_FAILED_VERIFICATION
		 */
		memset(certs, 0, sizeof(certs));
		memcpy(certs, f->cert_data, sizeof(certs));
		memset(f->cert_data, 0, sizeof(f->cert_data));
		cert = true;
	} else {
		LOG("Unknown cURL response code %d", result);
		error = true;
	}

	fetch_curl_stop(f);

	if (abort_fetch) {
		; /* fetch was aborted: no callback */
	} else if (finished) {
		fetch_msg msg;
		msg.type = FETCH_FINISHED;
		fetch_send_callback(&msg, f->fetch_handle);
	} else if (cert) {
		/* user needs to validate certificate with issue */
		curl_start_cert_validate(f, certs);
	} else if (error) {
		fetch_msg msg;
		switch (result) {
		case CURLE_SSL_CONNECT_ERROR:
			msg.type = FETCH_SSL_ERR;
			break;

		case CURLE_OPERATION_TIMEDOUT:
			msg.type = FETCH_TIMEDOUT;
			msg.data.error = curl_easy_strerror(result);
			break;

		default:
			msg.type = FETCH_ERROR;
			msg.data.error = curl_easy_strerror(result);
		}

		fetch_send_callback(&msg, f->fetch_handle);
	}

	fetch_free(f->fetch_handle);
}
示例#10
0
文件: curl.c 项目: EyMenZ/NetSurf-OS3
/**
 * Handle a completed fetch (CURLMSG_DONE from curl_multi_info_read()).
 *
 * \param curl_handle curl easy handle of fetch
 * \param result The result code of the completed fetch.
 */
static void fetch_curl_done(CURL *curl_handle, CURLcode result)
{
	fetch_msg msg;
	bool finished = false;
	bool error = false;
	bool cert = false;
	bool abort_fetch;
	struct curl_fetch_info *f;
	char **_hideous_hack = (char **) (void *) &f;
	CURLcode code;
	struct cert_info certs[MAX_CERTS];
	memset(certs, 0, sizeof(certs));

	/* find the structure associated with this fetch */
	/* For some reason, cURL thinks CURLINFO_PRIVATE should be a string?! */
	code = curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, _hideous_hack);
	assert(code == CURLE_OK);

	abort_fetch = f->abort;
	LOG("done %s", nsurl_access(f->url));

	if (abort_fetch == false && (result == CURLE_OK ||
			(result == CURLE_WRITE_ERROR && f->stopped == false))) {
		/* fetch completed normally or the server fed us a junk gzip
		 * stream (usually in the form of garbage at the end of the
		 * stream). Curl will have fed us all but the last chunk of
		 * decoded data, which is sad as, if we'd received the last
		 * chunk, too, we'd be able to render the whole object.
		 * As is, we'll just have to accept that the end of the
		 * object will be truncated in this case and leave it to
		 * the content handlers to cope.
		 */
		if (f->stopped ||
				(!f->had_headers &&
					fetch_curl_process_headers(f)))
			; /* redirect with no body or similar */
		else
			finished = true;
	} else if (result == CURLE_PARTIAL_FILE) {
		/* CURLE_PARTIAL_FILE occurs if the received body of a
		 * response is smaller than that specified in the
		 * Content-Length header. */
		if (!f->had_headers && fetch_curl_process_headers(f))
			; /* redirect with partial body, or similar */
		else {
			finished = true;
		}
	} else if (result == CURLE_WRITE_ERROR && f->stopped) {
		/* CURLE_WRITE_ERROR occurs when fetch_curl_data
		 * returns 0, which we use to abort intentionally */
		;
	} else if (result == CURLE_SSL_PEER_CERTIFICATE ||
			result == CURLE_SSL_CACERT) {
		memcpy(certs, f->cert_data, sizeof(certs));
		memset(f->cert_data, 0, sizeof(f->cert_data));
		cert = true;
	} else {
		LOG("Unknown cURL response code %d", result);
		error = true;
	}

	fetch_curl_stop(f);

	if (abort_fetch)
		; /* fetch was aborted: no callback */
	else if (finished) {
		msg.type = FETCH_FINISHED;
		fetch_send_callback(&msg, f->fetch_handle);
	} else if (cert) {
		int i;
		BIO *mem;
		BUF_MEM *buf;
		struct ssl_cert_info ssl_certs[MAX_CERTS];

		for (i = 0; i < MAX_CERTS && certs[i].cert; i++) {
			ssl_certs[i].version =
				X509_get_version(certs[i].cert);

			mem = BIO_new(BIO_s_mem());
			ASN1_TIME_print(mem,
					X509_get_notBefore(certs[i].cert));
			BIO_get_mem_ptr(mem, &buf);
			(void) BIO_set_close(mem, BIO_NOCLOSE);
			BIO_free(mem);
			memcpy(ssl_certs[i].not_before,
			       buf->data,
			       min(sizeof(ssl_certs[i].not_before) - 1,
				   (unsigned)buf->length));
			ssl_certs[i].not_before[min(sizeof(ssl_certs[i].not_before) - 1,
						    (unsigned)buf->length)] = 0;
			BUF_MEM_free(buf);

			mem = BIO_new(BIO_s_mem());
			ASN1_TIME_print(mem,
					X509_get_notAfter(certs[i].cert));
			BIO_get_mem_ptr(mem, &buf);
			(void) BIO_set_close(mem, BIO_NOCLOSE);
			BIO_free(mem);
			memcpy(ssl_certs[i].not_after,
			       buf->data,
			       min(sizeof(ssl_certs[i].not_after) - 1,
				   (unsigned)buf->length));
			ssl_certs[i].not_after[min(sizeof(ssl_certs[i].not_after) - 1,
						 (unsigned)buf->length)] = 0;

			BUF_MEM_free(buf);

			ssl_certs[i].sig_type =
				X509_get_signature_type(certs[i].cert);
			ssl_certs[i].serial =
				ASN1_INTEGER_get(
					X509_get_serialNumber(certs[i].cert));
			mem = BIO_new(BIO_s_mem());
			X509_NAME_print_ex(mem,
				X509_get_issuer_name(certs[i].cert),
				0, XN_FLAG_SEP_CPLUS_SPC |
					XN_FLAG_DN_REV | XN_FLAG_FN_NONE);
			BIO_get_mem_ptr(mem, &buf);
			(void) BIO_set_close(mem, BIO_NOCLOSE);
			BIO_free(mem);
			memcpy(ssl_certs[i].issuer,
			       buf->data,
			       min(sizeof(ssl_certs[i].issuer) - 1,
				   (unsigned) buf->length));
			ssl_certs[i].issuer[min(sizeof(ssl_certs[i].issuer) - 1,
						(unsigned) buf->length)] = 0;
			BUF_MEM_free(buf);

			mem = BIO_new(BIO_s_mem());
			X509_NAME_print_ex(mem,
				X509_get_subject_name(certs[i].cert),
					   0,
					   XN_FLAG_SEP_CPLUS_SPC |
					   XN_FLAG_DN_REV |
					   XN_FLAG_FN_NONE);
			BIO_get_mem_ptr(mem, &buf);
			(void) BIO_set_close(mem, BIO_NOCLOSE);
			BIO_free(mem);
			memcpy(ssl_certs[i].subject,
			       buf->data,
			       min(sizeof(ssl_certs[i].subject) - 1,
				   (unsigned)buf->length));
			ssl_certs[i].subject[min(sizeof(ssl_certs[i].subject) - 1,
						 (unsigned) buf->length)] = 0;
			BUF_MEM_free(buf);

			ssl_certs[i].cert_type =
				X509_certificate_type(certs[i].cert,
					X509_get_pubkey(certs[i].cert));

			/* and clean up */
			certs[i].cert->references--;
			if (certs[i].cert->references == 0)
				X509_free(certs[i].cert);
		}

		msg.type = FETCH_CERT_ERR;
		msg.data.cert_err.certs = ssl_certs;
		msg.data.cert_err.num_certs = i;
		fetch_send_callback(&msg, f->fetch_handle);
	} else if (error) {
		switch (result) {
		case CURLE_SSL_CONNECT_ERROR:
			msg.type = FETCH_SSL_ERR;
			break;

		case CURLE_OPERATION_TIMEDOUT:
			msg.type = FETCH_TIMEDOUT;
			msg.data.error = curl_easy_strerror(result);
			break;

		default:
			msg.type = FETCH_ERROR;
			msg.data.error = curl_easy_strerror(result);
		}

		fetch_send_callback(&msg, f->fetch_handle);
	}

	fetch_free(f->fetch_handle);
}