input/Soup: move code into the class
This commit is contained in:
		| @@ -72,6 +72,15 @@ struct SoupInputStream { | ||||
| 	bool completed; | ||||
|  | ||||
| 	GError *postponed_error; | ||||
|  | ||||
| 	SoupInputStream(const char *uri, Mutex &mutex, Cond &cond); | ||||
| 	~SoupInputStream(); | ||||
|  | ||||
| 	bool CopyError(const SoupMessage *msg); | ||||
|  | ||||
| 	bool WaitData(); | ||||
|  | ||||
| 	size_t Read(void *ptr, size_t size, GError **error_r); | ||||
| }; | ||||
|  | ||||
| static inline GQuark | ||||
| @@ -127,31 +136,31 @@ input_soup_finish(void) | ||||
|  * | ||||
|  * @return true if there was no error | ||||
|  */ | ||||
| static bool | ||||
| input_soup_copy_error(SoupInputStream *s, const SoupMessage *msg) | ||||
| bool | ||||
| SoupInputStream::CopyError(const SoupMessage *src) | ||||
| { | ||||
| 	if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) | ||||
| 	if (SOUP_STATUS_IS_SUCCESSFUL(src->status_code)) | ||||
| 		return true; | ||||
|  | ||||
| 	if (msg->status_code == SOUP_STATUS_CANCELLED) | ||||
| 	if (src->status_code == SOUP_STATUS_CANCELLED) | ||||
| 		/* failure, but don't generate a GError, because this | ||||
| 		   status was caused by _close() */ | ||||
| 		return false; | ||||
|  | ||||
| 	if (s->postponed_error != NULL) | ||||
| 	if (postponed_error != nullptr) | ||||
| 		/* there's already a GError, don't overwrite it */ | ||||
| 		return false; | ||||
|  | ||||
| 	if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) | ||||
| 		s->postponed_error = | ||||
| 			g_error_new(soup_quark(), msg->status_code, | ||||
| 	if (SOUP_STATUS_IS_TRANSPORT_ERROR(src->status_code)) | ||||
| 		postponed_error = | ||||
| 			g_error_new(soup_quark(), src->status_code, | ||||
| 				    "HTTP client error: %s", | ||||
| 				    msg->reason_phrase); | ||||
| 				    src->reason_phrase); | ||||
| 	else | ||||
| 		s->postponed_error = | ||||
| 			g_error_new(soup_quark(), msg->status_code, | ||||
| 		postponed_error = | ||||
| 			g_error_new(soup_quark(), src->status_code, | ||||
| 				    "got HTTP status: %d %s", | ||||
| 				    msg->status_code, msg->reason_phrase); | ||||
| 				    src->status_code, src->reason_phrase); | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
| @@ -168,7 +177,7 @@ input_soup_session_callback(G_GNUC_UNUSED SoupSession *session, | ||||
| 	const ScopeLock protect(*s->base.mutex); | ||||
|  | ||||
| 	if (!s->base.ready) | ||||
| 		input_soup_copy_error(s, msg); | ||||
| 		s->CopyError(msg); | ||||
|  | ||||
| 	s->base.ready = true; | ||||
| 	s->alive = false; | ||||
| @@ -184,7 +193,7 @@ input_soup_got_headers(SoupMessage *msg, gpointer user_data) | ||||
|  | ||||
| 	s->base.mutex->lock(); | ||||
|  | ||||
| 	if (!input_soup_copy_error(s, msg)) { | ||||
| 	if (!s->CopyError(msg)) { | ||||
| 		s->base.mutex->unlock(); | ||||
|  | ||||
| 		soup_session_cancel_message(soup_session, msg, | ||||
| @@ -237,22 +246,22 @@ input_soup_got_body(G_GNUC_UNUSED SoupMessage *msg, gpointer user_data) | ||||
| 	s->base.mutex->unlock(); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| input_soup_wait_data(SoupInputStream *s) | ||||
| inline bool | ||||
| SoupInputStream::WaitData() | ||||
| { | ||||
| 	while (true) { | ||||
| 		if (s->eof) | ||||
| 		if (eof) | ||||
| 			return true; | ||||
|  | ||||
| 		if (!s->alive) | ||||
| 		if (!alive) | ||||
| 			return false; | ||||
|  | ||||
| 		if (!g_queue_is_empty(s->buffers)) | ||||
| 		if (!g_queue_is_empty(buffers)) | ||||
| 			return true; | ||||
|  | ||||
| 		assert(s->current_consumed == 0); | ||||
| 		assert(current_consumed == 0); | ||||
|  | ||||
| 		s->base.cond->wait(*s->base.mutex); | ||||
| 		base.cond->wait(*base.mutex); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -267,22 +276,16 @@ input_soup_queue(gpointer data) | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static struct input_stream * | ||||
| input_soup_open(const char *uri, | ||||
| 		Mutex &mutex, Cond &cond, | ||||
| 		G_GNUC_UNUSED GError **error_r) | ||||
| SoupInputStream::SoupInputStream(const char *uri, | ||||
| 				 Mutex &mutex, Cond &cond) | ||||
| 	:buffers(g_queue_new()), | ||||
| 	 current_consumed(0), total_buffered(0), | ||||
| 	 alive(false), pause(false), eof(false), completed(false), | ||||
| 	 postponed_error(nullptr) | ||||
| { | ||||
| 	if (strncmp(uri, "http://", 7) != 0) | ||||
| 		return NULL; | ||||
|  | ||||
| 	SoupInputStream *s = g_new(SoupInputStream, 1); | ||||
| 	input_stream_init(&s->base, &input_plugin_soup, uri, | ||||
| 	input_stream_init(&base, &input_plugin_soup, uri, | ||||
| 			  mutex, cond); | ||||
|  | ||||
| 	s->buffers = g_queue_new(); | ||||
| 	s->current_consumed = 0; | ||||
| 	s->total_buffered = 0; | ||||
|  | ||||
| #if GCC_CHECK_VERSION(4,6) | ||||
| #pragma GCC diagnostic push | ||||
| 	/* the libsoup macro SOUP_METHOD_GET discards the "const" | ||||
| @@ -291,32 +294,36 @@ input_soup_open(const char *uri, | ||||
| #pragma GCC diagnostic ignored "-Wcast-qual" | ||||
| #endif | ||||
|  | ||||
| 	s->msg = soup_message_new(SOUP_METHOD_GET, uri); | ||||
| 	msg = soup_message_new(SOUP_METHOD_GET, uri); | ||||
|  | ||||
| #if GCC_CHECK_VERSION(4,6) | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
|  | ||||
| 	soup_message_set_flags(s->msg, SOUP_MESSAGE_NO_REDIRECT); | ||||
| 	soup_message_set_flags(msg, SOUP_MESSAGE_NO_REDIRECT); | ||||
|  | ||||
| 	soup_message_headers_append(s->msg->request_headers, "User-Agent", | ||||
| 	soup_message_headers_append(msg->request_headers, "User-Agent", | ||||
| 				    "Music Player Daemon " VERSION); | ||||
|  | ||||
| 	g_signal_connect(s->msg, "got-headers", | ||||
| 			 G_CALLBACK(input_soup_got_headers), s); | ||||
| 	g_signal_connect(s->msg, "got-chunk", | ||||
| 			 G_CALLBACK(input_soup_got_chunk), s); | ||||
| 	g_signal_connect(s->msg, "got-body", | ||||
| 			 G_CALLBACK(input_soup_got_body), s); | ||||
| 	g_signal_connect(msg, "got-headers", | ||||
| 			 G_CALLBACK(input_soup_got_headers), this); | ||||
| 	g_signal_connect(msg, "got-chunk", | ||||
| 			 G_CALLBACK(input_soup_got_chunk), this); | ||||
| 	g_signal_connect(msg, "got-body", | ||||
| 			 G_CALLBACK(input_soup_got_body), this); | ||||
|  | ||||
| 	s->alive = true; | ||||
| 	s->pause = false; | ||||
| 	s->eof = false; | ||||
| 	s->completed = false; | ||||
| 	s->postponed_error = NULL; | ||||
| 	io_thread_call(input_soup_queue, this); | ||||
| } | ||||
|  | ||||
| 	io_thread_call(input_soup_queue, s); | ||||
| static struct input_stream * | ||||
| input_soup_open(const char *uri, | ||||
| 		Mutex &mutex, Cond &cond, | ||||
| 		G_GNUC_UNUSED GError **error_r) | ||||
| { | ||||
| 	if (strncmp(uri, "http://", 7) != 0) | ||||
| 		return NULL; | ||||
|  | ||||
| 	SoupInputStream *s = new SoupInputStream(uri, mutex, cond); | ||||
| 	return &s->base; | ||||
| } | ||||
|  | ||||
| @@ -332,38 +339,42 @@ input_soup_cancel(gpointer data) | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| SoupInputStream::~SoupInputStream() | ||||
| { | ||||
| 	base.mutex->lock(); | ||||
|  | ||||
| 	if (!completed) { | ||||
| 		/* the messages's session callback hasn't been invoked | ||||
| 		   yet; cancel it and wait for completion */ | ||||
|  | ||||
| 		base.mutex->unlock(); | ||||
|  | ||||
| 		io_thread_call(input_soup_cancel, this); | ||||
|  | ||||
| 		base.mutex->lock(); | ||||
| 		while (!completed) | ||||
| 			base.cond->wait(*base.mutex); | ||||
| 	} | ||||
|  | ||||
| 	base.mutex->unlock(); | ||||
|  | ||||
| 	SoupBuffer *buffer; | ||||
| 	while ((buffer = (SoupBuffer *)g_queue_pop_head(buffers)) != NULL) | ||||
| 		soup_buffer_free(buffer); | ||||
| 	g_queue_free(buffers); | ||||
|  | ||||
| 	if (postponed_error != NULL) | ||||
| 		g_error_free(postponed_error); | ||||
|  | ||||
| 	input_stream_deinit(&base); | ||||
| } | ||||
|  | ||||
| static void | ||||
| input_soup_close(struct input_stream *is) | ||||
| { | ||||
| 	SoupInputStream *s = (SoupInputStream *)is; | ||||
|  | ||||
| 		s->base.mutex->lock(); | ||||
|  | ||||
| 	if (!s->completed) { | ||||
| 		/* the messages's session callback hasn't been invoked | ||||
| 		   yet; cancel it and wait for completion */ | ||||
|  | ||||
| 		s->base.mutex->unlock(); | ||||
|  | ||||
| 		io_thread_call(input_soup_cancel, s); | ||||
|  | ||||
| 		s->base.mutex->lock(); | ||||
| 		while (!s->completed) | ||||
| 			s->base.cond->wait(*s->base.mutex); | ||||
| 	} | ||||
|  | ||||
| 	s->base.mutex->unlock(); | ||||
|  | ||||
| 	SoupBuffer *buffer; | ||||
| 	while ((buffer = (SoupBuffer *)g_queue_pop_head(s->buffers)) != NULL) | ||||
| 		soup_buffer_free(buffer); | ||||
| 	g_queue_free(s->buffers); | ||||
|  | ||||
| 	if (s->postponed_error != NULL) | ||||
| 		g_error_free(s->postponed_error); | ||||
|  | ||||
| 	input_stream_deinit(&s->base); | ||||
| 	g_free(s); | ||||
| 	delete s; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| @@ -388,18 +399,15 @@ input_soup_available(struct input_stream *is) | ||||
| 	return s->eof || !s->alive || !g_queue_is_empty(s->buffers); | ||||
| } | ||||
|  | ||||
| static size_t | ||||
| input_soup_read(struct input_stream *is, void *ptr, size_t size, | ||||
| 		G_GNUC_UNUSED GError **error_r) | ||||
| inline size_t | ||||
| SoupInputStream::Read(void *ptr, size_t size, GError **error_r) | ||||
| { | ||||
| 	SoupInputStream *s = (SoupInputStream *)is; | ||||
| 	if (!WaitData()) { | ||||
| 		assert(!alive); | ||||
|  | ||||
| 	if (!input_soup_wait_data(s)) { | ||||
| 		assert(!s->alive); | ||||
|  | ||||
| 		if (s->postponed_error != NULL) { | ||||
| 			g_propagate_error(error_r, s->postponed_error); | ||||
| 			s->postponed_error = NULL; | ||||
| 		if (postponed_error != nullptr) { | ||||
| 			g_propagate_error(error_r, postponed_error); | ||||
| 			postponed_error = nullptr; | ||||
| 		} else | ||||
| 			g_set_error_literal(error_r, soup_quark(), 0, | ||||
| 					    "HTTP failure"); | ||||
| @@ -410,19 +418,19 @@ input_soup_read(struct input_stream *is, void *ptr, size_t size, | ||||
|  | ||||
| 	while (p < p_end) { | ||||
| 		SoupBuffer *buffer = (SoupBuffer *) | ||||
| 			g_queue_pop_head(s->buffers); | ||||
| 			g_queue_pop_head(buffers); | ||||
| 		if (buffer == NULL) { | ||||
| 			assert(s->current_consumed == 0); | ||||
| 			assert(current_consumed == 0); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		assert(s->current_consumed < buffer->length); | ||||
| 		assert(s->total_buffered >= buffer->length); | ||||
| 		assert(current_consumed < buffer->length); | ||||
| 		assert(total_buffered >= buffer->length); | ||||
|  | ||||
| 		const char *q = buffer->data; | ||||
| 		q += s->current_consumed; | ||||
| 		q += current_consumed; | ||||
|  | ||||
| 		size_t remaining = buffer->length - s->current_consumed; | ||||
| 		size_t remaining = buffer->length - current_consumed; | ||||
| 		size_t nbytes = p_end - p; | ||||
| 		if (nbytes > remaining) | ||||
| 			nbytes = remaining; | ||||
| @@ -430,31 +438,40 @@ input_soup_read(struct input_stream *is, void *ptr, size_t size, | ||||
| 		memcpy(p, q, nbytes); | ||||
| 		p += nbytes; | ||||
|  | ||||
| 		s->current_consumed += remaining; | ||||
| 		if (s->current_consumed >= buffer->length) { | ||||
| 		current_consumed += remaining; | ||||
| 		if (current_consumed >= buffer->length) { | ||||
| 			/* done with this buffer */ | ||||
| 			s->total_buffered -= buffer->length; | ||||
| 			total_buffered -= buffer->length; | ||||
| 			soup_buffer_free(buffer); | ||||
| 			s->current_consumed = 0; | ||||
| 			current_consumed = 0; | ||||
| 		} else { | ||||
| 			/* partial read */ | ||||
| 			assert(p == p_end); | ||||
|  | ||||
| 			g_queue_push_head(s->buffers, buffer); | ||||
| 			g_queue_push_head(buffers, buffer); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (s->pause && s->total_buffered < SOUP_RESUME_AT) { | ||||
| 		s->pause = false; | ||||
| 		soup_session_unpause_message(soup_session, s->msg); | ||||
| 	if (pause && total_buffered < SOUP_RESUME_AT) { | ||||
| 		pause = false; | ||||
| 		soup_session_unpause_message(soup_session, msg); | ||||
| 	} | ||||
|  | ||||
| 	size_t nbytes = p - p0; | ||||
| 	s->base.offset += nbytes; | ||||
| 	base.offset += nbytes; | ||||
|  | ||||
| 	return nbytes; | ||||
| } | ||||
|  | ||||
| static size_t | ||||
| input_soup_read(struct input_stream *is, void *ptr, size_t size, | ||||
| 		GError **error_r) | ||||
| { | ||||
| 	SoupInputStream *s = (SoupInputStream *)is; | ||||
|  | ||||
| 	return s->Read(ptr, size, error_r); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| input_soup_eof(G_GNUC_UNUSED struct input_stream *is) | ||||
| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann