mirror of
https://github.com/libretro/RetroArch
synced 2025-02-28 22:13:51 +00:00
(net_http.c) Cleanups
This commit is contained in:
parent
d8fd5e14d0
commit
e893f98787
499
net_http.c
499
net_http.c
@ -33,8 +33,9 @@ enum
|
||||
|
||||
enum
|
||||
{
|
||||
t_full,
|
||||
t_len, t_chunk
|
||||
T_FULL = 0,
|
||||
T_LEN,
|
||||
T_CHUNK
|
||||
};
|
||||
|
||||
static bool net_http_parse_url(char *url, char **domain,
|
||||
@ -80,60 +81,60 @@ static int net_http_new_socket(const char * domain, int port)
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
#else
|
||||
struct timeval timeout;
|
||||
struct timeval timeout;
|
||||
#endif
|
||||
struct addrinfo hints, *addr = NULL;
|
||||
char portstr[16];
|
||||
struct addrinfo hints, *addr = NULL;
|
||||
char portstr[16];
|
||||
|
||||
snprintf(portstr, sizeof(portstr), "%i", port);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = 0;
|
||||
|
||||
if (getaddrinfo_rarch(domain, portstr, &hints, &addr) < 0)
|
||||
snprintf(portstr, sizeof(portstr), "%i", port);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = 0;
|
||||
|
||||
if (getaddrinfo_rarch(domain, portstr, &hints, &addr) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
(void)i;
|
||||
|
||||
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
#ifndef _WIN32
|
||||
timeout.tv_sec=4;
|
||||
timeout.tv_usec=0;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout);
|
||||
timeout.tv_sec=4;
|
||||
timeout.tv_usec=0;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout);
|
||||
#endif
|
||||
|
||||
if (connect(fd, addr->ai_addr, addr->ai_addrlen) != 0)
|
||||
{
|
||||
freeaddrinfo_rarch(addr);
|
||||
socket_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo_rarch(addr);
|
||||
|
||||
if (!socket_nonblock(fd))
|
||||
if (connect(fd, addr->ai_addr, addr->ai_addrlen) != 0)
|
||||
{
|
||||
socket_close(fd);
|
||||
freeaddrinfo_rarch(addr);
|
||||
socket_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
freeaddrinfo_rarch(addr);
|
||||
|
||||
if (!socket_nonblock(fd))
|
||||
{
|
||||
socket_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void net_http_send(int fd, bool * error,
|
||||
const char * data, size_t len)
|
||||
{
|
||||
if (*error)
|
||||
if (*error)
|
||||
return;
|
||||
|
||||
while (len)
|
||||
{
|
||||
ssize_t thislen = send(fd, data, len, MSG_NOSIGNAL);
|
||||
while (len)
|
||||
{
|
||||
ssize_t thislen = send(fd, data, len, MSG_NOSIGNAL);
|
||||
|
||||
if (thislen <= 0)
|
||||
if (thislen <= 0)
|
||||
{
|
||||
if (!isagain(thislen))
|
||||
continue;
|
||||
@ -142,14 +143,14 @@ static void net_http_send(int fd, bool * error,
|
||||
return;
|
||||
}
|
||||
|
||||
data += thislen;
|
||||
len -= thislen;
|
||||
}
|
||||
data += thislen;
|
||||
len -= thislen;
|
||||
}
|
||||
}
|
||||
|
||||
static void net_http_send_str(int fd, bool *error, const char *text)
|
||||
{
|
||||
net_http_send(fd, error, text, strlen(text));
|
||||
net_http_send(fd, error, text, strlen(text));
|
||||
}
|
||||
|
||||
static ssize_t net_http_recv(int fd, bool *error,
|
||||
@ -175,297 +176,295 @@ static ssize_t net_http_recv(int fd, bool *error,
|
||||
|
||||
http_t *net_http_new(const char * url)
|
||||
{
|
||||
bool error;
|
||||
bool error;
|
||||
char *domain = NULL, *location = NULL;
|
||||
int port = 0, fd = -1;
|
||||
http_t *state = NULL;
|
||||
char *urlcopy =(char*)malloc(strlen(url)+1);
|
||||
int port = 0, fd = -1;
|
||||
http_t *state = NULL;
|
||||
char *urlcopy =(char*)malloc(strlen(url)+1);
|
||||
|
||||
strcpy(urlcopy, url);
|
||||
strcpy(urlcopy, url);
|
||||
|
||||
if (!net_http_parse_url(urlcopy, &domain, &port, &location))
|
||||
if (!net_http_parse_url(urlcopy, &domain, &port, &location))
|
||||
goto fail;
|
||||
|
||||
fd = net_http_new_socket(domain, port);
|
||||
if (fd == -1)
|
||||
fd = net_http_new_socket(domain, port);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
error=false;
|
||||
|
||||
/* This is a bit lazy, but it works. */
|
||||
net_http_send_str(fd, &error, "GET /");
|
||||
net_http_send_str(fd, &error, location);
|
||||
net_http_send_str(fd, &error, " HTTP/1.1\r\n");
|
||||
|
||||
net_http_send_str(fd, &error, "Host: ");
|
||||
net_http_send_str(fd, &error, domain);
|
||||
|
||||
if (port!=80)
|
||||
{
|
||||
char portstr[16];
|
||||
error=false;
|
||||
|
||||
snprintf(portstr, sizeof(portstr), ":%i", port);
|
||||
net_http_send_str(fd, &error, portstr);
|
||||
}
|
||||
/* This is a bit lazy, but it works. */
|
||||
net_http_send_str(fd, &error, "GET /");
|
||||
net_http_send_str(fd, &error, location);
|
||||
net_http_send_str(fd, &error, " HTTP/1.1\r\n");
|
||||
|
||||
net_http_send_str(fd, &error, "\r\n");
|
||||
net_http_send_str(fd, &error, "Connection: close\r\n");
|
||||
net_http_send_str(fd, &error, "\r\n");
|
||||
|
||||
if (error)
|
||||
net_http_send_str(fd, &error, "Host: ");
|
||||
net_http_send_str(fd, &error, domain);
|
||||
|
||||
if (port!=80)
|
||||
{
|
||||
char portstr[16];
|
||||
|
||||
snprintf(portstr, sizeof(portstr), ":%i", port);
|
||||
net_http_send_str(fd, &error, portstr);
|
||||
}
|
||||
|
||||
net_http_send_str(fd, &error, "\r\n");
|
||||
net_http_send_str(fd, &error, "Connection: close\r\n");
|
||||
net_http_send_str(fd, &error, "\r\n");
|
||||
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
free(urlcopy);
|
||||
|
||||
state = (http_t*)malloc(sizeof(http_t));
|
||||
state->fd = fd;
|
||||
state->status = -1;
|
||||
state->data = NULL;
|
||||
state->part = p_header_top;
|
||||
state->bodytype= t_full;
|
||||
state->error = false;
|
||||
state->pos = 0;
|
||||
state->len = 0;
|
||||
state->buflen = 512;
|
||||
state->data = (char*)malloc(state->buflen);
|
||||
|
||||
return state;
|
||||
|
||||
free(urlcopy);
|
||||
|
||||
state = (http_t*)malloc(sizeof(http_t));
|
||||
state->fd = fd;
|
||||
state->status = -1;
|
||||
state->data = NULL;
|
||||
state->part = p_header_top;
|
||||
state->bodytype= T_FULL;
|
||||
state->error = false;
|
||||
state->pos = 0;
|
||||
state->len = 0;
|
||||
state->buflen = 512;
|
||||
state->data = (char*)malloc(state->buflen);
|
||||
|
||||
return state;
|
||||
|
||||
fail:
|
||||
if (fd != -1)
|
||||
if (fd != -1)
|
||||
socket_close(fd);
|
||||
free(urlcopy);
|
||||
return NULL;
|
||||
free(urlcopy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int net_http_fd(http_t *state)
|
||||
{
|
||||
return state->fd;
|
||||
return state->fd;
|
||||
}
|
||||
|
||||
bool net_http_update(http_t *state, size_t* progress, size_t* total)
|
||||
{
|
||||
ssize_t newlen = 0;
|
||||
|
||||
if (state->error)
|
||||
ssize_t newlen = 0;
|
||||
|
||||
if (state->error)
|
||||
goto fail;
|
||||
|
||||
if (state->part < p_body)
|
||||
{
|
||||
newlen = net_http_recv(state->fd, &state->error,
|
||||
|
||||
if (state->part < p_body)
|
||||
{
|
||||
newlen = net_http_recv(state->fd, &state->error,
|
||||
(uint8_t*)state->data + state->pos, state->buflen - state->pos);
|
||||
|
||||
if (newlen < 0)
|
||||
if (newlen < 0)
|
||||
goto fail;
|
||||
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
state->pos += newlen;
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
state->pos += newlen;
|
||||
|
||||
while (state->part < p_body)
|
||||
{
|
||||
char *dataend = state->data + state->pos;
|
||||
char *lineend = (char*)memchr(state->data, '\n', state->pos);
|
||||
while (state->part < p_body)
|
||||
{
|
||||
char *dataend = state->data + state->pos;
|
||||
char *lineend = (char*)memchr(state->data, '\n', state->pos);
|
||||
|
||||
if (!lineend)
|
||||
if (!lineend)
|
||||
break;
|
||||
*lineend='\0';
|
||||
if (lineend != state->data && lineend[-1]=='\r')
|
||||
*lineend='\0';
|
||||
if (lineend != state->data && lineend[-1]=='\r')
|
||||
lineend[-1]='\0';
|
||||
|
||||
if (state->part == p_header_top)
|
||||
{
|
||||
if (strncmp(state->data, "HTTP/1.", strlen("HTTP/1."))!=0)
|
||||
|
||||
if (state->part == p_header_top)
|
||||
{
|
||||
if (strncmp(state->data, "HTTP/1.", strlen("HTTP/1."))!=0)
|
||||
goto fail;
|
||||
state->status=strtoul(state->data + strlen("HTTP/1.1 "), NULL, 10);
|
||||
state->part = p_header;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strncmp(state->data, "Content-Length: ",
|
||||
state->status=strtoul(state->data + strlen("HTTP/1.1 "), NULL, 10);
|
||||
state->part = p_header;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strncmp(state->data, "Content-Length: ",
|
||||
strlen("Content-Length: ")))
|
||||
{
|
||||
state->bodytype = t_len;
|
||||
state->len = strtol(state->data +
|
||||
{
|
||||
state->bodytype = T_LEN;
|
||||
state->len = strtol(state->data +
|
||||
strlen("Content-Length: "), NULL, 10);
|
||||
}
|
||||
if (!strcmp(state->data, "Transfer-Encoding: chunked"))
|
||||
{
|
||||
state->bodytype=t_chunk;
|
||||
}
|
||||
}
|
||||
if (!strcmp(state->data, "Transfer-Encoding: chunked"))
|
||||
state->bodytype = T_CHUNK;
|
||||
|
||||
/* TODO: save headers somewhere */
|
||||
if (state->data[0]=='\0')
|
||||
{
|
||||
state->part = p_body;
|
||||
if (state->bodytype == t_chunk)
|
||||
/* TODO: save headers somewhere */
|
||||
if (state->data[0]=='\0')
|
||||
{
|
||||
state->part = p_body;
|
||||
if (state->bodytype == T_CHUNK)
|
||||
state->part = p_body_chunklen;
|
||||
}
|
||||
}
|
||||
|
||||
memmove(state->data, lineend + 1, dataend-(lineend+1));
|
||||
state->pos = (dataend-(lineend + 1));
|
||||
}
|
||||
if (state->part >= p_body)
|
||||
{
|
||||
newlen = state->pos;
|
||||
state->pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state->part >= p_body && state->part < p_done)
|
||||
{
|
||||
if (!newlen)
|
||||
{
|
||||
newlen = net_http_recv(state->fd, &state->error,
|
||||
memmove(state->data, lineend + 1, dataend-(lineend+1));
|
||||
state->pos = (dataend-(lineend + 1));
|
||||
}
|
||||
if (state->part >= p_body)
|
||||
{
|
||||
newlen = state->pos;
|
||||
state->pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->part >= p_body && state->part < p_done)
|
||||
{
|
||||
if (!newlen)
|
||||
{
|
||||
newlen = net_http_recv(state->fd, &state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
|
||||
if (newlen < 0)
|
||||
{
|
||||
if (state->bodytype == t_full)
|
||||
{
|
||||
if (newlen < 0)
|
||||
{
|
||||
if (state->bodytype == T_FULL)
|
||||
{
|
||||
state->part = p_done;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
newlen=0;
|
||||
}
|
||||
newlen=0;
|
||||
}
|
||||
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
}
|
||||
|
||||
parse_again:
|
||||
if (state->bodytype == t_chunk)
|
||||
{
|
||||
if (state->part == p_body_chunklen)
|
||||
{
|
||||
state->pos += newlen;
|
||||
if (state->pos - state->len >= 2)
|
||||
{
|
||||
/*
|
||||
if (state->bodytype == T_CHUNK)
|
||||
{
|
||||
if (state->part == p_body_chunklen)
|
||||
{
|
||||
state->pos += newlen;
|
||||
if (state->pos - state->len >= 2)
|
||||
{
|
||||
/*
|
||||
* len=start of chunk including \r\n
|
||||
* pos=end of data
|
||||
*/
|
||||
|
||||
char *fullend = state->data + state->pos;
|
||||
char *end = (char*)memchr(state->data + state->len + 2,
|
||||
char *fullend = state->data + state->pos;
|
||||
char *end = (char*)memchr(state->data + state->len + 2,
|
||||
'\n', state->pos - state->len - 2);
|
||||
|
||||
if (end)
|
||||
{
|
||||
size_t chunklen = strtoul(state->data+state->len, NULL, 16);
|
||||
state->pos = state->len;
|
||||
end++;
|
||||
if (end)
|
||||
{
|
||||
size_t chunklen = strtoul(state->data+state->len, NULL, 16);
|
||||
state->pos = state->len;
|
||||
end++;
|
||||
|
||||
memmove(state->data+state->len, end, fullend-end);
|
||||
memmove(state->data+state->len, end, fullend-end);
|
||||
|
||||
state->len = chunklen;
|
||||
newlen = (fullend - end);
|
||||
state->len = chunklen;
|
||||
newlen = (fullend - end);
|
||||
|
||||
/*
|
||||
len=num bytes
|
||||
newlen=unparsed bytes after \n
|
||||
pos=start of chunk including \r\n
|
||||
*/
|
||||
len=num bytes
|
||||
newlen=unparsed bytes after \n
|
||||
pos=start of chunk including \r\n
|
||||
*/
|
||||
|
||||
state->part = p_body;
|
||||
if (state->len == 0)
|
||||
{
|
||||
state->part = p_done;
|
||||
state->len = state->pos;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
goto parse_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state->part == p_body)
|
||||
{
|
||||
if ((size_t)newlen >= state->len)
|
||||
{
|
||||
state->pos += state->len;
|
||||
newlen -= state->len;
|
||||
state->len = state->pos;
|
||||
state->part = p_body_chunklen;
|
||||
goto parse_again;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->pos += newlen;
|
||||
state->len -= newlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state->pos += newlen;
|
||||
state->part = p_body;
|
||||
if (state->len == 0)
|
||||
{
|
||||
state->part = p_done;
|
||||
state->len = state->pos;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
goto parse_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state->part == p_body)
|
||||
{
|
||||
if ((size_t)newlen >= state->len)
|
||||
{
|
||||
state->pos += state->len;
|
||||
newlen -= state->len;
|
||||
state->len = state->pos;
|
||||
state->part = p_body_chunklen;
|
||||
goto parse_again;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->pos += newlen;
|
||||
state->len -= newlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state->pos += newlen;
|
||||
|
||||
if (state->pos == state->len)
|
||||
{
|
||||
if (state->pos == state->len)
|
||||
{
|
||||
state->part=p_done;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
if (state->pos > state->len)
|
||||
}
|
||||
if (state->pos > state->len)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
*progress = state->pos;
|
||||
|
||||
if (total)
|
||||
{
|
||||
if (state->bodytype == t_len)
|
||||
if (total)
|
||||
{
|
||||
if (state->bodytype == T_LEN)
|
||||
*total=state->len;
|
||||
else
|
||||
else
|
||||
*total=0;
|
||||
}
|
||||
|
||||
return (state->part==p_done);
|
||||
|
||||
fail:
|
||||
state->error = true;
|
||||
state->part = p_error;
|
||||
state->status = -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
return (state->part==p_done);
|
||||
|
||||
fail:
|
||||
state->error = true;
|
||||
state->part = p_error;
|
||||
state->status = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int net_http_status(http_t *state)
|
||||
{
|
||||
return state->status;
|
||||
return state->status;
|
||||
}
|
||||
|
||||
uint8_t* net_http_data(http_t *state, size_t* len, bool accept_error)
|
||||
{
|
||||
if (!accept_error &&
|
||||
if (!accept_error &&
|
||||
(state->error || state->status<200 || state->status>299))
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
if (len)
|
||||
*len=0;
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len)
|
||||
if (len)
|
||||
*len=state->len;
|
||||
|
||||
return (uint8_t*)state->data;
|
||||
return (uint8_t*)state->data;
|
||||
}
|
||||
|
||||
void net_http_delete(http_t *state)
|
||||
{
|
||||
if (state->fd != -1)
|
||||
if (state->fd != -1)
|
||||
socket_close(state->fd);
|
||||
if (state->data)
|
||||
if (state->data)
|
||||
free(state->data);
|
||||
free(state);
|
||||
free(state);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user