/**Parse HTTP query string. * * The function http_query_parse() searches for the given keys in HTTP @a * query. For each key, a query element (in the form name=value) is searched * from the query string. If a query element has a beginning matching with * the key, a copy of the rest of the element is returned in corresponding * return_value argument. * * @note The @a query string will be modified. * * @return * The function http_query_parse() returns number keys that matched within * the @a query string. */ issize_t http_query_parse(char *query, /* char const *key, char **return_value, */ ...) { va_list ap; char *q, *q_next; char *name, *value, **return_value; char const *key; size_t namelen, valuelen, keylen; isize_t N; int has_value; if (!query) return -1; for (q = query, N = 0; *q; q = q_next) { namelen = strcspn(q, "=&"); valuelen = namelen + strcspn(q + namelen, "&"); q_next = q + valuelen; if (*q_next) *q_next++ = '\0'; value = q + namelen; has_value = (*value) != '\0'; /* is the part in form of name=value? */ if (has_value) *value++ = '\0'; name = url_unescape(q, q); if (has_value) { namelen = strlen(name); name[namelen] = '='; url_unescape(name + namelen + 1, value); } va_start(ap, query); while ((key = va_arg(ap, char const *))) { return_value = va_arg(ap, char **); keylen = strlen(key); if (strncmp(key, name, keylen) == 0) { *return_value = name + keylen; N++; } } va_end(ap); } return N; }
int main(int argc, char *argv[]) { int fd; char name[64], *buf, *out = NULL, *verify; size_t len, outlen; buf = get_file_buffer(argv[1], &len); if (buf) { if (argc > 2) { if (url_unescape(buf, len, &out, &outlen) == 0) { printf("%.*s\n", (int)outlen, out); if ((verify = url_escape(out, outlen))) { fd = get_tmpfile(name, 0666, NULL, NULL); if (fd > 0) { printf("verify file:%s\n", name); write(fd, verify, strlen(verify)); close(fd); } } } } else { if ((out = url_escape(buf, len))) printf("%s\n", out); } free(buf); if (out) free(out); } }
/** * Create a path from a nsurl using amiga file handling. * * @param[in] url The url to encode. * @param[out] path_out A string containing the result path which should * be freed by the caller. * @return NSERROR_OK and the path is written to \a path or error code * on faliure. */ static nserror amiga_nsurl_to_path(struct nsurl *url, char **path_out) { lwc_string *urlpath; char *path; bool match; lwc_string *scheme; nserror res; char *colon; char *slash; if ((url == NULL) || (path_out == NULL)) { return NSERROR_BAD_PARAMETER; } scheme = nsurl_get_component(url, NSURL_SCHEME); if (lwc_string_caseless_isequal(scheme, corestring_lwc_file, &match) != lwc_error_ok) { return NSERROR_BAD_PARAMETER; } lwc_string_unref(scheme); if (match == false) { return NSERROR_BAD_PARAMETER; } urlpath = nsurl_get_component(url, NSURL_PATH); if (urlpath == NULL) { return NSERROR_BAD_PARAMETER; } res = url_unescape(lwc_string_data(urlpath) + 1, &path); lwc_string_unref(urlpath); if (res != NSERROR_OK) { return res; } colon = strchr(path, ':'); if(colon == NULL) { slash = strchr(path, '/'); if(slash) { *slash = ':'; } else { int len = strlen(path); path[len] = ':'; path[len + 1] = '\0'; } } *path_out = path; return NSERROR_OK; }
static char *url_to_path(const char *url) { char *url_path; char *path = NULL; if (url_unescape(url, 0, &url_path) == NSERROR_OK) { /* return the absolute path including leading / */ path = strdup(url_path + (FILE_SCHEME_PREFIX_LEN - 1)); free(url_path); } return path; }
/** * Try and find the correct RISC OS filetype from a download context. */ static nserror download_ro_filetype(download_context *ctx, bits *ftype_out) { nsurl *url = download_context_get_url(ctx); bits ftype = 0; lwc_string *scheme; /* If the file is local try and read its filetype */ scheme = nsurl_get_component(url, NSURL_SCHEME); if (scheme != NULL) { bool filescheme; if (lwc_string_isequal(scheme, corestring_lwc_file, &filescheme) != lwc_error_ok) { filescheme = false; } if (filescheme) { lwc_string *path = nsurl_get_component(url, NSURL_PATH); if (path != NULL && lwc_string_length(path) != 0) { char *raw_path; if (url_unescape(lwc_string_data(path), lwc_string_length(path), &raw_path) == NSERROR_OK) { ftype = ro_filetype_from_unix_path(raw_path); free(raw_path); } } } } /* If we still don't have a filetype (i.e. failed reading local * one or fetching a remote object), then use the MIME type. */ if (ftype == 0) { /* convert MIME type to RISC OS file type */ os_error *error; const char *mime_type; mime_type = download_context_get_mime_type(ctx); error = xmimemaptranslate_mime_type_to_filetype(mime_type, &ftype); if (error) { LOG("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("MiscError", error->errmess); ftype = 0xffd; } } *ftype_out = ftype; return NSERROR_OK; }
char *url_to_path(const char *url) { char *path; char *respath; url_func_result res; /* result from url routines */ res = url_path(url, &path); if (res != URL_FUNC_OK) { return NULL; } res = url_unescape(path, &respath); free(path); if (res != URL_FUNC_OK) { return NULL; } return respath; }
int url_2char_canonical (url_t * url, char **dest) { int result; *dest = NULL; result = url_2char (url, dest); if (result == 0) { /* tmp = strchr(*dest, ";"); if (tmp !=NULL) { buf=strndup(*dest, tmp-(*dest)); sfree(*dest); *dest=buf; } */ url_unescape (*dest); } return result; }
char *url_to_path(const char *url) { char *unesc, *slash, *colon, *url2; if (strncmp(url, "file://", SLEN("file://")) != 0) return NULL; url += SLEN("file://"); if (strncmp(url, "localhost", SLEN("localhost")) == 0) url += SLEN("localhost"); if (strncmp(url, "/", SLEN("/")) == 0) url += SLEN("/"); if(*url == '\0') return NULL; /* file:/// is not a valid path */ url2 = malloc(strlen(url) + 2); strcpy(url2, url); colon = strchr(url2, ':'); if(colon == NULL) { if(slash = strchr(url2, '/')) { *slash = ':'; } else { int len = strlen(url2); url2[len] = ':'; url2[len + 1] = '\0'; } } if(url_unescape(url2,&unesc) == URL_FUNC_OK) return unesc; return (char *)url2; }
struct magnet_resource * magnet_parse(const char *url, const char **error_str) { static const struct magnet_resource zero_resource; struct magnet_resource res; const char *p, *next; res = zero_resource; clear_error_str(&error_str); p = is_strcaseprefix(url, "magnet:"); if (!p) { *error_str = "Not a MAGNET URI"; return NULL; } if ('?' != p[0]) { *error_str = "Invalid MAGNET URI"; return NULL; } p++; for (/* NOTHING */; p && '\0' != p[0]; p = next) { enum magnet_key key; const char *endptr; char name[16]; /* Large enough to hold longest key we know */ name[0] = '\0'; endptr = strchr(p, '='); if (endptr && p != endptr) { size_t name_len; name_len = endptr - p; g_assert(size_is_positive(name_len)); if (name_len < sizeof name) { /* Ignore overlong key */ strncat(name, p, name_len); } p = &endptr[1]; /* Point behind the '=' */ } endptr = strchr(p, '&'); if (!endptr) { endptr = strchr(p, '\0'); } key = magnet_key_get(name); if (MAGNET_KEY_NONE == key) { g_message("skipping unknown key \"%s\" in MAGNET URI", name); } else { char *value; size_t value_len; value_len = endptr - p; value = h_strndup(p, value_len); plus_to_space(value); if (url_unescape(value, TRUE)) { magnet_handle_key(&res, name, value); } else { g_message("badly encoded value in MAGNET URI: \"%s\"", value); } HFREE_NULL(value); } while ('&' == endptr[0]) { endptr++; } next = endptr; } res.sources = g_slist_reverse(res.sources); res.searches = g_slist_reverse(res.searches); return wcopy(&res, sizeof res); }
static bool fetch_data_process(struct fetch_data_context *c) { nserror res; fetch_msg msg; char *params; char *comma; char *unescaped; size_t unescaped_len; /* format of a data: URL is: * data:[<mimetype>][;base64],<data> * The mimetype is optional. If it is missing, the , before the * data must still be there. */ NSLOG(netsurf, INFO, "url: %.140s", c->url); if (strlen(c->url) < 6) { /* 6 is the minimum possible length (data:,) */ msg.type = FETCH_ERROR; msg.data.error = "Malformed data: URL"; fetch_data_send_callback(&msg, c); return false; } /* skip the data: part */ params = c->url + SLEN("data:"); /* find the comma */ if ( (comma = strchr(params, ',')) == NULL) { msg.type = FETCH_ERROR; msg.data.error = "Malformed data: URL"; fetch_data_send_callback(&msg, c); return false; } if (params[0] == ',') { /* there is no mimetype here, assume text/plain */ c->mimetype = strdup("text/plain;charset=US-ASCII"); } else { /* make a copy of everything between data: and the comma */ c->mimetype = strndup(params, comma - params); } if (c->mimetype == NULL) { msg.type = FETCH_ERROR; msg.data.error = "Unable to allocate memory for mimetype in data: URL"; fetch_data_send_callback(&msg, c); return false; } if (strcmp(c->mimetype + strlen(c->mimetype) - 7, ";base64") == 0) { c->base64 = true; c->mimetype[strlen(c->mimetype) - 7] = '\0'; } else { c->base64 = false; } /* URL unescape the data first, just incase some insane page * decides to nest URL and base64 encoding. Like, say, Acid2. */ res = url_unescape(comma + 1, 0, &unescaped_len, &unescaped); if (res != NSERROR_OK) { msg.type = FETCH_ERROR; msg.data.error = "Unable to URL decode data: URL"; fetch_data_send_callback(&msg, c); return false; } if (c->base64) { if ((nsu_base64_decode_alloc((uint8_t *)unescaped, unescaped_len, (uint8_t **)&c->data, &c->datalen) != NSUERROR_OK) || (c->data == NULL)) { msg.type = FETCH_ERROR; msg.data.error = "Unable to Base64 decode data: URL"; fetch_data_send_callback(&msg, c); free(unescaped); return false; } } else { c->data = malloc(unescaped_len); if (c->data == NULL) { msg.type = FETCH_ERROR; msg.data.error = "Unable to allocate memory for data: URL"; fetch_data_send_callback(&msg, c); free(unescaped); return false; } c->datalen = unescaped_len; memcpy(c->data, unescaped, unescaped_len); } free(unescaped); return true; }
int url_parse_params (url_t * url, char *params) { char *pname; char *pvalue; char *comma; char *equal; /* find '=' wich is the separator for one param */ /* find ';' wich is the separator for multiple params */ equal = next_separator (params + 1, '=', ';'); comma = strchr (params + 1, ';'); while (comma != NULL) { if (equal == NULL) { equal = comma; pvalue = NULL; } else { if (comma - equal < 2) return -1; pvalue = (char *) smalloc (comma - equal); if (pvalue == NULL) return -1; sstrncpy (pvalue, equal + 1, comma - equal - 1); url_unescape (pvalue); } if (equal - params < 2) { sfree (pvalue); return -1; } pname = (char *) smalloc (equal - params); if (pname == NULL) { sfree (pvalue); return -1; } sstrncpy (pname, params + 1, equal - params - 1); url_unescape (pname); url_uparam_add (url, pname, pvalue); params = comma; equal = next_separator (params + 1, '=', ';'); comma = strchr (params + 1, ';'); } /* this is the last header (comma==NULL) */ comma = params + strlen (params); if (equal == NULL) { equal = comma; /* at the end */ pvalue = NULL; } else { if (comma - equal < 2) return -1; pvalue = (char *) smalloc (comma - equal); if (pvalue == NULL) return -1; sstrncpy (pvalue, equal + 1, comma - equal - 1); } if (equal - params < 2) { sfree (pvalue); return -1; } pname = (char *) smalloc (equal - params); if (pname == NULL) { sfree (pvalue); return -1; } sstrncpy (pname, params + 1, equal - params - 1); url_uparam_add (url, pname, pvalue); return 0; }
int url_parse_headers (url_t * url, char *headers) { char *and; char *equal; /* find '=' wich is the separator for one header */ /* find ';' wich is the separator for multiple headers */ equal = strchr (headers, '='); and = strchr (headers + 1, '&'); if (equal == NULL) /* each header MUST have a value */ return -1; do { char *hname; char *hvalue; hname = (char *) smalloc (equal - headers); if (hname == NULL) return -1; sstrncpy (hname, headers + 1, equal - headers - 1); url_unescape (hname); if (and != NULL) { if (and - equal < 2) { sfree (hname); return -1; } hvalue = (char *) smalloc (and - equal); if (hvalue == NULL) { sfree (hname); return -1; } sstrncpy (hvalue, equal + 1, and - equal - 1); url_unescape (hvalue); } else { /* this is for the last header (no and...) */ if (headers + strlen (headers) - equal + 1 < 2) { sfree (hname); return -1; } hvalue = (char *) smalloc (headers + strlen (headers) - equal + 1); if (hvalue == NULL) { sfree (hname); return -1; } sstrncpy (hvalue, equal + 1, headers + strlen (headers) - equal); url_unescape (hvalue); } url_uheader_add (url, hname, hvalue); if (and == NULL) /* we just set the last header */ equal = NULL; else /* continue on next header */ { headers = and; equal = strchr (headers, '='); and = strchr (headers + 1, '&'); if (equal == NULL) /* each header MUST have a value */ return -1; } } while (equal != NULL); return 0; }
/* return -1 on error */ int url_parse (url_t * url, char *buf) { char *username; char *password; char *host; char *port; char *params; char *headers; char *tmp; /* basic tests */ if (buf == NULL) return -1; tmp = strchr (buf, ':'); if (tmp == NULL) return -1; if (tmp - buf < 2) return -1; url->scheme = (char *) smalloc (tmp - buf + 1); if (url->scheme == NULL) return -1; sstrncpy (url->scheme, buf, tmp - buf); #if (!defined WIN32 && !defined _WIN32_WCE) if (strlen (url->scheme) < 3 || (0 != strncasecmp (url->scheme, "sip", 3) && 0 != strncasecmp (url->scheme, "sips", 4))) { /* Is not a sipurl ! */ int i = strlen (tmp + 1); if (i < 2) return -1; url->string = (char *) smalloc (i + 1); if (url->string == NULL) return -1; sstrncpy (url->string, tmp + 1, i); return 0; } #else if (strlen (url->scheme) < 3 || (0 != _strnicmp (url->scheme, "sip", 3) && 0 != _strnicmp (url->scheme, "sips", 4))) { /* Is not a sipurl ! */ int i = strlen (tmp + 1); if (i < 2) return -1; url->string = (char *) smalloc (i + 1); if (url->string == NULL) return -1; sstrncpy (url->string, tmp + 1, i); return 0; } #endif /* law number 1: if ('?' exists && is_located_after '@') or if ('?' exists && '@' is not there -no username-) =====> HEADER_PARAM EXIST =====> start at index(?) =====> end at the end of url */ /* find the beginning of host */ username = strchr (buf, ':'); /* if ':' does not exist, the url is not valid */ if (username == NULL) return -1; host = strchr (buf, '@'); if (host == NULL) host = username; else /* username exists */ { password = next_separator (username + 1, ':', '@'); if (password == NULL) password = host; else /* password exists */ { if (host - password < 2) return -1; url->password = (char *) smalloc (host - password); if (url->password == NULL) return -1; sstrncpy (url->password, password + 1, host - password - 1); url_unescape (url->password); } if (password - username < 2) return -1; { url->username = (char *) smalloc (password - username); if (url->username == NULL) return -1; sstrncpy (url->username, username + 1, password - username - 1); url_unescape (url->username); } } /* search for header after host */ headers = strchr (host, '?'); if (headers == NULL) headers = buf + strlen (buf); else /* headers exist */ url_parse_headers (url, headers); /* search for params after host */ params = strchr (host, ';'); /* search for params after host */ if (params == NULL) params = headers; else /* params exist */ { if (headers - params + 1 < 2) return -1; tmp = smalloc (headers - params + 1); if (tmp == NULL) return -1; tmp = sstrncpy (tmp, params, headers - params); url_parse_params (url, tmp); sfree (tmp); } port = params - 1; while (port > host && *port != ']' && *port != ':') port--; if (*port == ':') { if (host == port) port = params; else { if ((params - port < 2) || (params - port > 8)) return -1; /* error cases */ url->port = (char *) smalloc (params - port); if (url->port == NULL) return -1; sstrncpy (url->port, port + 1, params - port - 1); sclrspace (url->port); } } else port = params; /* adjust port for ipv6 address */ tmp = port; while (tmp > host && *tmp != ']') tmp--; if (*tmp == ']') { port = tmp; while (host < port && *host != '[') host++; if (host >= port) return -1; } if (port - host < 2) return -1; url->host = (char *) smalloc (port - host); if (url->host == NULL) return -1; sstrncpy (url->host, host + 1, port - host - 1); sclrspace (url->host); return 0; }
G_GNUC_COLD void upload_stats_load_history(void) { FILE *upload_stats_file; file_path_t fp; char line[FILENAME_MAX + 64]; guint lineno = 0; gcu_upload_stats_gui_freeze(); file_path_set(&fp, settings_config_dir(), ul_stats_file); /* open file for reading */ upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1); if (upload_stats_file == NULL) goto done; /* parse, insert names into ul_stats_clist */ while (fgets(line, sizeof(line), upload_stats_file)) { static const struct ul_stats zero_item; struct ul_stats item; struct sha1 sha1_buf; const char *p; size_t i; lineno++; if (line[0] == '#' || line[0] == '\n') continue; p = strchr(line, '\t'); if (NULL == p) goto corrupted; line[p - line] = '\0'; /* line is now the URL-escaped file name */ p++; /* URL-unescape in-place */ if (!url_unescape(line, TRUE)) goto corrupted; item = zero_item; item.pathname = line; for (i = 0; i < 8; i++) { guint64 v; int error; const char *endptr; p = skip_ascii_spaces(p); /* SVN versions up to 15322 had only 6 fields in the history */ if (5 == i && '\0' == *p) break; switch (i) { case 7: /* We have a SHA1 or '*' if none known */ if ('*' != *p) { size_t len = clamp_strlen(p, SHA1_BASE32_SIZE); error = !parse_base32_sha1(p, len, &sha1_buf); item.sha1 = error ? NULL : &sha1_buf; } else { error = FALSE; } p = skip_ascii_non_spaces(p); v = 0; break; default: v = parse_uint64(p, &endptr, 10, &error); p = deconstify_gchar(endptr); } if (error || !is_ascii_space(*endptr)) goto corrupted; switch (i) { case 0: item.size = v; break; case 1: item.attempts = v; break; case 2: item.complete = v; break; case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break; case 4: item.bytes_sent |= (guint32) v; break; case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 7: break; /* Already stored above */ default: g_assert_not_reached(); goto corrupted; } } /* * We store the filenames UTF-8 encoded but the file might have been * edited or corrupted. */ if (is_absolute_path(item.pathname)) { item.filename = lazy_filename_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC); } else { item.filename = lazy_unknown_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC, NULL); } if (upload_stats_find(NULL, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else if (upload_stats_find(item.sha1, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else { upload_stats_add(item.pathname, item.size, item.filename, item.attempts, item.complete, item.bytes_sent, item.rtime, item.dtime, item.sha1); } continue; corrupted: g_warning("upload statistics file corrupted at line %u.", lineno); } /* close file */ fclose(upload_stats_file); done: gcu_upload_stats_gui_thaw(); return; }
/** * Open a TFTP connection to the server * * @param:inode, the inode to store our state in * @param:ip, the ip to contact to get the file * @param:filename, the file we wanna open * * @out: open_file_t structure, stores in file->open_file * @out: the lenght of this file, stores in file->file_len * */ void tftp_open(struct url_info *url, int flags, struct inode *inode, const char **redir) { struct pxe_pvt_inode *socket = PVT(inode); char *buf; uint16_t buf_len; char *p; char *options; char *data; static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408"; char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail]; char reply_packet_buf[PKTBUF_SIZE]; int err; int buffersize; int rrq_len; const uint8_t *timeout_ptr; jiffies_t timeout; jiffies_t oldtime; uint16_t opcode; uint16_t blk_num; uint64_t opdata; uint16_t src_port; uint32_t src_ip; (void)redir; /* TFTP does not redirect */ (void)flags; if (url->type != URL_OLD_TFTP) { /* * The TFTP URL specification allows the TFTP to end with a * ;mode= which we just ignore. */ url_unescape(url->path, ';'); } if (!url->port) url->port = TFTP_PORT; socket->ops = &tftp_conn_ops; if (core_udp_open(socket)) return; buf = rrq_packet_buf; *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */ buf += 2; buf = stpcpy(buf, url->path); buf++; /* Point *past* the final NULL */ memcpy(buf, rrq_tail, sizeof rrq_tail); buf += sizeof rrq_tail; rrq_len = buf - rrq_packet_buf; timeout_ptr = TimeoutTable; /* Reset timeout */ sendreq: timeout = *timeout_ptr++; if (!timeout) return; /* No file available... */ oldtime = jiffies(); core_udp_sendto(socket, rrq_packet_buf, rrq_len, url->ip, url->port); /* If the WRITE call fails, we let the timeout take care of it... */ wait_pkt: for (;;) { buf_len = sizeof(reply_packet_buf); err = core_udp_recv(socket, reply_packet_buf, &buf_len, &src_ip, &src_port); if (err) { jiffies_t now = jiffies(); if (now - oldtime >= timeout) goto sendreq; } else { /* Make sure the packet actually came from the server and is long enough for a TFTP opcode */ dprintf("tftp_open: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n", buf_len, ((uint8_t *)&src_ip)[0], ((uint8_t *)&src_ip)[1], ((uint8_t *)&src_ip)[2], ((uint8_t *)&src_ip)[3], ((uint8_t *)&url->ip)[0], ((uint8_t *)&url->ip)[1], ((uint8_t *)&url->ip)[2], ((uint8_t *)&url->ip)[3]); if ((src_ip == url->ip) && (buf_len >= 2)) break; } } core_udp_disconnect(socket); core_udp_connect(socket, src_ip, src_port); /* filesize <- -1 == unknown */ inode->size = -1; socket->tftp_blksize = TFTP_BLOCKSIZE; buffersize = buf_len - 2; /* bytes after opcode */ /* * Get the opcode type, and parse it */ opcode = *(uint16_t *)reply_packet_buf; switch (opcode) { case TFTP_ERROR: inode->size = 0; goto done; /* ERROR reply; don't try again */ case TFTP_DATA: /* * If the server doesn't support any options, we'll get a * DATA reply instead of OACK. Stash the data in the file * buffer and go with the default value for all options... * * We got a DATA packet, meaning no options are * suported. Save the data away and consider the * length undefined, *unless* this is the only * data packet... */ buffersize -= 2; if (buffersize < 0) goto wait_pkt; data = reply_packet_buf + 2; blk_num = ntohs(*(uint16_t *)data); data += 2; if (blk_num != 1) goto wait_pkt; socket->tftp_lastpkt = blk_num; if (buffersize > TFTP_BLOCKSIZE) goto err_reply; /* Corrupt */ socket->tftp_pktbuf = malloc(TFTP_BLOCKSIZE + 4); if (!socket->tftp_pktbuf) goto err_reply; /* Internal error */ if (buffersize < TFTP_BLOCKSIZE) { /* * This is the final EOF packet, already... * We know the filesize, but we also want to * ack the packet and set the EOF flag. */ inode->size = buffersize; socket->tftp_goteof = 1; ack_packet(inode, blk_num); } socket->tftp_bytesleft = buffersize; socket->tftp_dataptr = socket->tftp_pktbuf; memcpy(socket->tftp_pktbuf, data, buffersize); goto done; case TFTP_OACK: /* * Now we need to parse the OACK packet to get the transfer * and packet sizes. */ options = reply_packet_buf + 2; p = options; while (buffersize) { const char *opt = p; /* * If we find an option which starts with a NUL byte, * (a null option), we're either seeing garbage that some * TFTP servers add to the end of the packet, or we have * no clue how to parse the rest of the packet (what is * an option name and what is a value?) In either case, * discard the rest. */ if (!*opt) goto done; while (buffersize) { if (!*p) break; /* Found a final null */ *p++ |= 0x20; buffersize--; } if (!buffersize) break; /* Unterminated option */ /* Consume the terminal null */ p++; buffersize--; if (!buffersize) break; /* No option data */ opdata = 0; /* do convert a number-string to decimal number, just like atoi */ while (buffersize--) { uint8_t d = *p++; if (d == '\0') break; /* found a final null */ d -= '0'; if (d > 9) goto err_reply; /* Not a decimal digit */ opdata = opdata*10 + d; } if (!strcmp(opt, "tsize")) inode->size = opdata; else if (!strcmp(opt, "blksize")) socket->tftp_blksize = opdata; else goto err_reply; /* Non-negotitated option returned, no idea what it means ...*/ } if (socket->tftp_blksize < 64 || socket->tftp_blksize > PKTBUF_SIZE) goto err_reply; /* Parsing successful, allocate buffer */ socket->tftp_pktbuf = malloc(socket->tftp_blksize + 4); if (!socket->tftp_pktbuf) goto err_reply; else goto done; default: printf("TFTP unknown opcode %d\n", ntohs(opcode)); goto err_reply; } err_reply: /* Build the TFTP error packet */ tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error"); inode->size = 0; done: if (!inode->size) core_udp_close(socket); return; }
/** * Send a file to a TFTP server * * @param:inode, the inode to store our state in * @param:ip, the ip to contact to get the file * @param:filename, the file we wanna push * * @out: open_file_t structure, stores in file->open_file * @out: the lenght of this file, stores in file->file_len * */ __export int tftp_put(struct url_info *url, int flags, struct inode *inode, const char **redir, char *data, int data_length) { struct pxe_pvt_inode *socket = PVT(inode); char *buf; uint16_t buf_len; static const char wrq_tail[] = "octet"; char wrq_packet_buf[512+4+6]; char reply_packet_buf[PKTBUF_SIZE]; int err; int wrq_len; const uint8_t *timeout_ptr; jiffies_t timeout; jiffies_t oldtime; uint16_t opcode; uint16_t src_port = url->port; uint32_t src_ip; uint16_t seq = 0; size_t chunk = 0; int len = data_length; int return_code = -ntohs(TFTP_EUNDEF); (void)redir; /* TFTP does not redirect */ (void)flags; if (url->type != URL_OLD_TFTP) { /* * The TFTP URL specification allows the TFTP to end with a * ;mode= which we just ignore. */ url_unescape(url->path, ';'); } if (!src_port) src_port = TFTP_PORT; // socket->ops = &tftp_conn_ops; if (core_udp_open(socket)) return return_code; buf = wrq_packet_buf; *(uint16_t *)buf = TFTP_WRQ; /* TFTP opcode */ buf += 2; buf += strlcpy(buf, url->path, 512); buf++; /* Point *past* the final NULL */ memcpy(buf, wrq_tail, sizeof wrq_tail); buf += sizeof wrq_tail; wrq_len = buf - wrq_packet_buf; timeout_ptr = TimeoutTable; /* Reset timeout */ sendreq: timeout = *timeout_ptr++; if (!timeout) return return_code; /* No file available... */ oldtime = jiffies(); core_udp_sendto(socket, wrq_packet_buf, wrq_len, url->ip, src_port); /* If the WRITE call fails, we let the timeout take care of it... */ for (;;) { buf_len = sizeof(reply_packet_buf); err = core_udp_recv(socket, reply_packet_buf, &buf_len, &src_ip, &src_port); if (err) { jiffies_t now = jiffies(); if (now - oldtime >= timeout) goto sendreq; } else { /* Make sure the packet actually came from the server and is long enough for a TFTP opcode */ dprintf("tftp_put: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n", buf_len, ((uint8_t *)&src_ip)[0], ((uint8_t *)&src_ip)[1], ((uint8_t *)&src_ip)[2], ((uint8_t *)&src_ip)[3], ((uint8_t *)&url->ip)[0], ((uint8_t *)&url->ip)[1], ((uint8_t *)&url->ip)[2], ((uint8_t *)&url->ip)[3]); if ((src_ip == url->ip) && (buf_len >= 2)) break; } } core_udp_disconnect(socket); core_udp_connect(socket, src_ip, src_port); /* filesize <- -1 == unknown */ inode->size = -1; socket->tftp_blksize = TFTP_BLOCKSIZE; /* * Get the opcode type, and parse it */ opcode = *(uint16_t *)reply_packet_buf; switch (opcode) { case TFTP_ERROR: dprintf("tftp_push: received a TFTP_ERROR\n"); struct tftp_error *te = (struct tftp_error *)(reply_packet_buf+1); return_code = -ntohs(te->errcode); inode->size = 0; goto done; /* ERROR reply; don't try again */ case TFTP_ACK: dprintf("tftp_push: received a TFTP_ACK\n"); /* We received a ACK packet, sending the associated data packet */ /* If data was completly sent, we can stop here */ if (len == 0) { return_code = -ntohs(TFTP_OK); goto done; } /* If the server sequence is not aligned with our, we have an issue * Let's break the transmission for now but could be improved later */ uint16_t srv_seq = ntohs(*(uint16_t *)(reply_packet_buf+2)); if (srv_seq != seq) { printf("tftp_push: server sequence (%"PRIu16") is not aligned with our sequence (%"PRIu16"\n", srv_seq, seq); return_code = -ntohs(TFTP_EBADOP); goto done; } /* Let's transmit the data block */ chunk = len >= 512 ? 512 : len; buf = wrq_packet_buf; *(uint16_t *)buf = TFTP_DATA; /* TFTP opcode */ *((uint16_t *)(buf+2)) = htons(++seq); memcpy(buf+4, data, chunk); wrq_len = chunk + 4; data += chunk; len -= chunk; timeout_ptr = TimeoutTable; /* Reset timeout */ goto sendreq; default: dprintf("tftp_push: unknown opcode %d\n", ntohs(opcode)); return_code = -ntohs(TFTP_EOPTNEG); goto err_reply; } err_reply: /* Build the TFTP error packet */ dprintf("tftp_push: Failure\n"); tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error"); inode->size = 0; done: if (!inode->size) core_udp_close(socket); return return_code; }
/* test unquoting and canonizing */ int test_quote(void) { su_home_t home[1] = { SU_HOME_INIT(home) }; url_t *u; char s[] = "%73ip:q%74est%01:%01%02%00@host%2enokia.com;%70aram=%01%02"; char c[] = "sip:qtest%01:%01%02%[email protected];param=%01%02"; char *d; #define RESERVED ";/?:@&=+$," #define DELIMS "<>#%\"" #define UNWISE "{}|\\^[]`" #define EXCLUDED RESERVED DELIMS UNWISE char escaped[1 + 3 * 23 + 1]; #define UNRESERVED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "abcdefghijklmnopqrstuvwxyz" \ "0123456789" \ "-_.!~*'()" char unreserved[26 + 26 + 10 + 9 + 1]; BEGIN(); d = url_as_string(home, (url_t *)"sip:[email protected]"); TEST_S(d, "sip:[email protected]"); TEST(strlen(EXCLUDED), 23); TEST(strlen(UNRESERVED), 71); TEST_1(!url_reserved_p("foo")); TEST_1(!url_reserved_p("")); TEST_1(url_reserved_p("foobar:bar")); TEST_SIZE(url_esclen("a" EXCLUDED, ""), 1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE)); TEST_SIZE(url_esclen("a" EXCLUDED, DELIMS UNWISE), 1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE)); TEST_SIZE(url_esclen("a" EXCLUDED, EXCLUDED), 1 + 3 * strlen(EXCLUDED)); TEST_SIZE(url_esclen("a" EXCLUDED, NULL), 1 + 3 * strlen(EXCLUDED)); TEST_S(url_escape(escaped, "a" EXCLUDED, NULL), "a%3B%2F%3F%3A%40%26%3D%2B%24%2C" "%3C%3E%23%25%22" "%7B%7D%7C%5C%5E%5B%5D%60"); TEST_S(url_unescape(escaped, escaped), "a" EXCLUDED); TEST_SIZE(url_esclen(UNRESERVED, NULL), strlen(UNRESERVED)); TEST_S(url_escape(unreserved, UNRESERVED, NULL), UNRESERVED); TEST_S(url_unescape(unreserved, UNRESERVED), UNRESERVED); d = "%53ip:%75@%48"; /* Sip:u@H */ u = url_hdup(home, (url_t *)d); TEST_1(u); url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); d = "sip:u@h"; u = url_hdup(home, (url_t *)d); TEST_1(u); url_digest(hash1, sizeof(hash1), u, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); u = url_hdup(home, (url_t *)s); TEST_1(u); d = url_as_string(home, u); TEST_1(d); TEST_S(d, c); d = "sip:&=+$,;?/:&=+$,@[::1]:56001;param=+$,/:@&;another=@%40%2F" "?header=" RESERVED "&%3b%2f%3f%3a%40%26%3d%2b%24%2c"; u = url_hdup(home, (url_t *)d); TEST_1(u); TEST_S(u->url_user, "&=+$,;?/"); TEST_S(u->url_host, "[::1]"); TEST_S(u->url_params, "param=+$,/:@&;another=@%40/"); TEST_S(u->url_headers, "header=" RESERVED "&%3B%2F%3F%3A%40%26%3D%2B%24%2C"); url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); u = url_hdup(home, (url_t *)s); TEST_1(u); d = url_as_string(home, u); TEST_1(d); TEST_S(d, c); d = "http://&=+$,;:&=+$,;@host:8080/foo%2F%3B%3D" ";param=+$,%2f%3b%3d/bar;param=:@&;another=@" "?query=" RESERVED; u = url_hdup(home, (url_t *)d); TEST_1(u); TEST_S(u->url_user, "&=+$,;"); TEST_S(u->url_password, "&=+$,;"); TEST_S(u->url_path, "foo%2F%3B%3D;param=+$,%2F%3B%3D/bar;param=:@&;another=@"); url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); u = url_hdup(home, (url_t *)s); TEST_1(u); d = url_as_string(home, u); TEST_1(d); TEST_S(d, c); url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)s, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); url_digest(hash2, sizeof(hash2), (url_t const *)c, NULL); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); END(); }