static void encoder_completed_cb (RBEncoder *encoder, guint64 dest_size, const char *mediatype, GError *error, RBTrackTransferBatch *batch) { RhythmDBEntry *entry; if (error != NULL) { rb_debug ("encoder finished (error: %s)", error->message); } else { rb_debug ("encoder finished (size %" G_GUINT64_FORMAT ")", dest_size); } g_object_unref (batch->priv->current_encoder); batch->priv->current_encoder = NULL; entry = batch->priv->current; batch->priv->current = NULL; /* update batch state to reflect that the track is done */ batch->priv->total_fraction += batch->priv->current_entry_fraction; batch->priv->done_entries = g_list_append (batch->priv->done_entries, entry); if (batch->priv->cancelled == FALSE) { /* keep ourselves alive until the end of the function, since it's * possible that a signal handler will cancel us. */ g_object_ref (batch); g_signal_emit (batch, signals[TRACK_DONE], 0, entry, batch->priv->current_dest_uri, dest_size, mediatype, error); start_next (batch); g_object_unref (batch); } }
static void track_transfer_completed (RBTrackTransferBatch *batch, guint64 dest_size, const char *mediatype, gboolean skipped, GError *error) { RhythmDBEntry *entry; entry = batch->priv->current; batch->priv->current = NULL; batch->priv->current_profile = NULL; /* update batch state to reflect that the track is done */ batch->priv->total_fraction += batch->priv->current_entry_fraction; batch->priv->done_entries = g_list_append (batch->priv->done_entries, entry); if (batch->priv->cancelled == FALSE) { /* keep ourselves alive until the end of the function, since it's * possible that a signal handler will cancel us. */ g_object_ref (batch); if (skipped == FALSE) { g_signal_emit (batch, signals[TRACK_DONE], 0, entry, batch->priv->current_dest_uri, dest_size, mediatype, error); } start_next (batch); g_object_unref (batch); } }
/** * _rb_track_transfer_batch_start: * @batch: a #RBTrackTransferBatch * @queue: the #RBTrackTransferQueue * * Starts the batch transfer. Only to be called by the #RBTrackTransferQueue. */ void _rb_track_transfer_batch_start (RBTrackTransferBatch *batch, GObject *queue) { gboolean total_duration_valid; gboolean total_size_valid; gboolean origin_valid; guint64 filesize; gulong duration; RBSource *origin = NULL; RBShell *shell; GList *l; g_object_get (queue, "shell", &shell, NULL); /* calculate total duration and file size and figure out the * origin source if we weren't given one to start with. */ total_duration_valid = TRUE; total_size_valid = TRUE; origin_valid = TRUE; for (l = batch->priv->entries; l != NULL; l = l->next) { RhythmDBEntry *entry = (RhythmDBEntry *)l->data; filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE); if (total_size_valid && filesize > 0) { batch->priv->total_size += filesize; } else { total_size_valid = FALSE; batch->priv->total_size = 0; } duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); if (total_duration_valid && duration > 0) { batch->priv->total_duration += duration; } else { total_duration_valid = FALSE; batch->priv->total_duration = 0; } if (batch->priv->source == NULL) { RhythmDBEntryType *entry_type; RBSource *entry_origin; entry_type = rhythmdb_entry_get_entry_type (entry); entry_origin = rb_shell_get_source_by_entry_type (shell, entry_type); if (origin == NULL && origin_valid == TRUE) { origin = entry_origin; } else if (origin != entry_origin) { origin = NULL; origin_valid = FALSE; } } } g_object_unref (shell); if (origin != NULL) { batch->priv->source = origin; } batch->priv->queue = RB_TRACK_TRANSFER_QUEUE (queue); batch->priv->cancelled = FALSE; batch->priv->total_fraction = 0.0; g_signal_emit (batch, signals[STARTED], 0); g_object_notify (G_OBJECT (batch), "task-progress"); g_object_notify (G_OBJECT (batch), "task-detail"); start_next (batch); }
/* * Parse the protocol and point relevant fields, don't take logic decisions * based on this, just parse to locate things. */ int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p, char *buffer, int buf_len, struct mk_server *server) { int s; int tmp; int ret; int len; /* lazy test printf("p->i=%i buf_len=%i\n", p->i, buf_len); for (s = p->i; s < buf_len; s++) { if (buffer[s] == '\r') { printf("CR"); } else if (buffer[s] == '\n') { printf("LF"); } else { printf("%c", buffer[s]); } } printf("\n"); */ len = buf_len; for (; p->i < len; p->i++, p->chars++) { /* FIRST LINE LEVEL: Method, URI & Protocol */ if (p->level == REQ_LEVEL_FIRST) { switch (p->status) { case MK_ST_REQ_METHOD: /* HTTP Method */ if (p->chars == -1) { switch (buffer[p->i]) { case 'G': p->method = MK_METHOD_GET; break; case 'P': p->method = MK_METHOD_POST; break; case 'H': p->method = MK_METHOD_HEAD; break; case 'D': p->method = MK_METHOD_DELETE; break; case 'O': p->method = MK_METHOD_OPTIONS; break; } continue; } if (buffer[p->i] == ' ') { mark_end(); p->status = MK_ST_REQ_URI; if (p->end < 2) { return MK_HTTP_PARSER_ERROR; } method_lookup(req, p, buffer); start_next(); } else { if ((p->i - p->start) > 10) { return MK_HTTP_PARSER_ERROR; } } break; case MK_ST_REQ_URI: /* URI */ if (buffer[p->i] == ' ') { mark_end(); p->status = MK_ST_REQ_PROT_VERSION; if (field_len() < 1) { return MK_HTTP_PARSER_ERROR; } request_set(&req->uri, p, buffer); start_next(); } else if (buffer[p->i] == '?') { mark_end(); request_set(&req->uri, p, buffer); p->status = MK_ST_REQ_QUERY_STRING; start_next(); } else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { mk_http_error(MK_CLIENT_BAD_REQUEST, req->session, req, server); return MK_HTTP_PARSER_ERROR; } break; case MK_ST_REQ_QUERY_STRING: /* Query string */ char_lookup(buffer, ' ', len, p); if (buffer[p->i] == ' ') { mark_end(); request_set(&req->query_string, p, buffer); p->status = MK_ST_REQ_PROT_VERSION; start_next(); } else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { mk_http_error(MK_CLIENT_BAD_REQUEST, req->session, req, server); return MK_HTTP_PARSER_ERROR; } break; case MK_ST_REQ_PROT_VERSION: /* Protocol Version */ /* * Most of the time we already have the string version in our * buffer, for that case try to match the version and avoid * loop rounds. */ if (p->start + 6 >= p->i) { continue; } tmp = p->start; if (buffer[tmp] == 'H' && buffer[tmp + 1] == 'T' && buffer[tmp + 2] == 'T' && buffer[tmp + 3] == 'P' && buffer[tmp + 4] == '/' && buffer[tmp + 5] == '1' && buffer[tmp + 6] == '.') { request_set(&req->protocol_p, p, buffer); req->protocol_p.len = 8; mk_http_set_minor_version(buffer[tmp + 7]); } else { mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP, req->session, req, server); return MK_HTTP_PARSER_ERROR; } p->status = MK_ST_FIRST_CONTINUE; break; case MK_ST_FIRST_CONTINUE: if (buffer[p->i] == '\r') { p->status = MK_ST_FIRST_FINALIZING; } else { return MK_HTTP_PARSER_ERROR; } break; case MK_ST_FIRST_FINALIZING: /* New Line */ if (buffer[p->i] == '\n') { p->level = REQ_LEVEL_CONTINUE; start_next(); } else { return MK_HTTP_PARSER_ERROR; } break; case MK_ST_BLOCK_END: if (buffer[p->i] == '\n') { return mk_http_parser_ok(req, p, server); } else { return MK_HTTP_PARSER_ERROR; } break; }; } else if (p->level == REQ_LEVEL_CONTINUE) { if (buffer[p->i] == '\r') { p->level = REQ_LEVEL_FIRST; p->status = MK_ST_BLOCK_END; } else { p->level = REQ_LEVEL_HEADERS; p->status = MK_ST_HEADER_KEY; p->chars = 0; } } /* HEADERS: all headers stuff */ if (p->level == REQ_LEVEL_HEADERS) { /* Expect a Header key */ if (p->status == MK_ST_HEADER_KEY) { if (buffer[p->i] == '\r') { if (p->chars == 0) { p->level = REQ_LEVEL_END; start_next(); } else { return MK_HTTP_PARSER_ERROR; } } if (p->chars == 0) { /* * We reach the start of a Header row, lets catch the most * probable header. * * The goal of this 'first row character lookup', is to define a * small range set of probable headers comparison once we catch * a header end. */ s = tolower(buffer[p->i]); switch (s) { case 'a': p->header_min = MK_HEADER_ACCEPT; p->header_max = MK_HEADER_AUTHORIZATION; break; case 'c': p->header_min = MK_HEADER_CACHE_CONTROL; p->header_max = MK_HEADER_CONTENT_TYPE; break; case 'h': p->header_min = MK_HEADER_HOST; p->header_max = MK_HEADER_HTTP2_SETTINGS; break; case 'i': header_scope_eq(p, MK_HEADER_IF_MODIFIED_SINCE); break; case 'l': p->header_min = MK_HEADER_LAST_MODIFIED; p->header_max = MK_HEADER_LAST_MODIFIED_SINCE; break; case 'r': p->header_min = MK_HEADER_RANGE; p->header_max = MK_HEADER_REFERER; break; case 'u': p->header_min = MK_HEADER_UPGRADE; p->header_max = MK_HEADER_USER_AGENT; break; default: p->header_key = -1; p->header_sep = -1; p->header_min = -1; p->header_max = -1; }; p->header_key = p->i; continue; } /* Found key/value separator */ char_lookup(buffer, ':', len, p); if (buffer[p->i] == ':') { /* Set the key/value middle point */ p->header_sep = p->i; /* validate length */ mark_end(); if (field_len() < 1) { return MK_HTTP_PARSER_ERROR; } /* Wait for a value */ p->status = MK_ST_HEADER_VALUE; start_next(); } } /* Parsing the header value */ else if (p->status == MK_ST_HEADER_VALUE) { /* Trim left, set starts only when found something != ' ' */ if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { return MK_HTTP_PARSER_ERROR; } else if (buffer[p->i] != ' ') { p->status = MK_ST_HEADER_VAL_STARTS; p->start = p->header_val = p->i; } continue; } /* New header row starts */ else if (p->status == MK_ST_HEADER_VAL_STARTS) { /* Maybe there is no more headers and we reach the end ? */ if (buffer[p->i] == '\r') { mark_end(); if (field_len() <= 0) { return MK_HTTP_PARSER_ERROR; } /* * A header row has ended, lets lookup the header and populate * our headers table index. */ ret = header_lookup(p, buffer); if (ret != 0) { if (ret < -1) { mk_http_error(-ret, req->session, req, server); } return MK_HTTP_PARSER_ERROR; } /* Try to catch next LF */ if (p->i + 1 < len) { if (buffer[p->i + 1] == '\n') { p->i++; p->status = MK_ST_HEADER_KEY; p->chars = -1; start_next(); } } p->status = MK_ST_HEADER_END; start_next(); } else if (buffer[p->i] == '\n' && buffer[p->i - 1] != '\r') { return MK_HTTP_PARSER_ERROR; } } else if (p->status == MK_ST_HEADER_END) { if (buffer[p->i] == '\n') { p->status = MK_ST_HEADER_KEY; p->chars = -1; start_next(); } else { return MK_HTTP_PARSER_ERROR; } } } else if (p->level == REQ_LEVEL_END) { if (buffer[p->i] == '\n') { if (p->header_content_length > 0) { p->level = REQ_LEVEL_BODY; p->chars = -1; start_next(); } else { return mk_http_parser_ok(req, p, server); } } else { return MK_HTTP_PARSER_ERROR; } } else if (p->level == REQ_LEVEL_BODY) { /* * Reaching this level can means two things: * * - A Pipeline Request * - A Body content (POST/PUT methods) */ if (p->header_content_length > 0) { p->body_received = len - p->start; if ((len - p->start) < p->header_content_length) { return MK_HTTP_PARSER_PENDING; } /* Cut off */ p->i += p->body_received; req->data.len = p->body_received; req->data.data = (buffer + p->start); } return mk_http_parser_ok(req, p, server); } } return MK_HTTP_PARSER_PENDING; }