Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
Split off Url to UrlParse; handle Http redirect
Browse files Browse the repository at this point in the history
  • Loading branch information
minexew committed Feb 8, 2017
1 parent dbfd7be commit d9d2c6b
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 141 deletions.
67 changes: 0 additions & 67 deletions Pkg/Pkg.HC
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#define PKG_EVERSION (-20004)
#define PKG_EOSVERSION (-20005)
#define PKG_EUNSUITABLE (-20006)
#define PKG_EEOF (-20007)

#define PKG_VERSION 10

Expand Down Expand Up @@ -38,72 +37,6 @@ static U8* StripDir(U8* file_path) {
return file_path;
}

// If this turns out to be useful, it might be moved into ShrineNet/Url
static I64 UrlGetWithProgress(U8* url, U8** data_out, I64* size_out) {
CUrl curl;
UrlInit(&curl);

I64 error = 0;
I64 size = 0;

if (UrlParse(url, &curl)) {
if (!StrCmp(curl.protocol, "http")) {
I64 sock = HttpOpenGet(curl.host, curl.port, curl.path, &size);

if (sock > 0) {
U8* data = MAlloc(1 + size);
I64 total = 0;
I64 progress = 0;
"[$FG,3$";

while (total < size) {
I64 step = size - total;

if (step > 1024)
step = 1024;

I64 got = recv(sock, data + total, step, 0);

if (got <= 0) {
error = PKG_EEOF;
break;
}

total += got;

I64 new_progress = (20 * total + size - 1) / size;
while (progress < new_progress) {
'' 0xfe;
progress++;
}
}

close(sock);

if (error) {
"$FG,4$x\n$FG$";
Free(data);
return error;
}

"$FG$]\n";
data[total] = 0;
*data_out = data;
*size_out = total;
}
else
error = sock;
}
else
error = URL_EPROTOCOL;
}
else
error = URL_EPARSE;

UrlFree(&curl);
return error;
}

U0 PkgInfoInit(CPkgInfo* pinf) {
pinf->package_name = 0;

Expand Down
2 changes: 2 additions & 0 deletions Shrine/mkdist.script
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ command DirMk("/Adam/Net");
put /Adam/Net/Http.HC.Z SnailNet/Http.HC
put /Adam/Net/Socket.HC.Z SnailNet/SocketDummy.HC
put /Adam/Net/Url.HC.Z SnailNet/Url.HC
put /Adam/Net/UrlParse.HC.Z SnailNet/UrlParse.HC

# Inject Pkg
put /Apps/Pkg.HC.Z Pkg/Pkg.HC
Expand Down Expand Up @@ -85,6 +86,7 @@ put /Tmp/SnailNet/Socket.HC.Z SnailNet/Socket.HC
put /Tmp/SnailNet/Tcp.HC.Z SnailNet/Tcp.HC
put /Tmp/SnailNet/Udp.HC.Z SnailNet/Udp.HC
put /Tmp/SnailNet/Url.HC.Z SnailNet/Url.HC
put /Tmp/SnailNet/UrlParse.HC.Z SnailNet/UrlParse.HC
put /Tmp/SnailNet.MF SnailNet/manifest
command PkgMakeFromDir("/Tmp/SnailNet.MF", "/Tmp/SnailNet");
list /Tmp/SnailNet.ISO.C PkgBin/SnailNet.ISO.C
Expand Down
64 changes: 58 additions & 6 deletions SnailNet/Http.HC
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
// vim: set ft=cpp:

#include "::/Adam/Net/Socket"
#include "::/Adam/Net/UrlParse"

#define HTTP_ECONNECT (-101)
#define HTTP_EPROTOCOL (-102)
#define HTTP_EREQUEST (-103)
#define HTTP_EREDIRECT (-104)
#define HTTP_EEOF (-105)

#define HTTP_MAX_REDIRECTS 5
#define HTTP_USER_AGENT "SnailNet ($TX+CX,"TempleOS",D="DD_OS_NAME_VERSION"$)"

I64 HttpOpenGet(U8* host, U16 port = 0, U8* path, I64* len_out) {
// Returns socket (>= 0) on success, error code on failure
I64 HttpOpenGet(U8* host, U16 port = 0, U8* path, I64* len_out,
I64 allowed_redirects = HTTP_MAX_REDIRECTS) {
U8 line[256];
I64 error = 0;

Expand All @@ -32,6 +38,9 @@ I64 HttpOpenGet(U8* host, U16 port = 0, U8* path, I64* len_out) {

Bool haveHTTP = FALSE;
Bool haveContentLength = FALSE;
U8* location = NULL;

I64 code = -1;

while (1) {
error = recvLine(sock, line, sizeof(line), 0);
Expand All @@ -45,19 +54,29 @@ I64 HttpOpenGet(U8* host, U16 port = 0, U8* path, I64* len_out) {
break;
}

U8* delim;

//"%s\n", line;
if (!haveHTTP) {
U8* code = StrFirstOcc(line, " ");
if (code && StrNCmp(line, "HTTP/", 5) == 0 && StrNCmp(code + 1, "200", 3) == 0) {
haveHTTP = TRUE;
delim = StrFirstOcc(line, " ");
if (delim && StrNCmp(line, "HTTP/", 5) == 0) {
code = Str2I64(delim + 1);

if (code >= 200 && code <= 399) {
haveHTTP = TRUE;
}
else {
error = HTTP_EREQUEST;
break;
}
}
else {
error = HTTP_EREQUEST;
break;
}
}
else {
U8* delim = StrFirstOcc(line, ":");
delim = StrFirstOcc(line, ":");

if (!delim) {
error = HTTP_EPROTOCOL;
Expand All @@ -74,8 +93,40 @@ I64 HttpOpenGet(U8* host, U16 port = 0, U8* path, I64* len_out) {
StrScan(delim, "%d", len_out);
haveContentLength = TRUE;
}
else if (!StrCmp(line, "Location")) {
location = StrNew(delim);
}
}
}

// HTTP Code 3xx -- Redirection
if (!error && code >= 300 && code <= 399) {
if (allowed_redirects > 0) {
CUrl curl;
UrlInit(&curl);

if (UrlParse(location, &curl)) {
if (!StrCmp(curl.protocol, "http")) {
close(sock);
sock = HttpOpenGet(curl.host, curl.port, curl.path, len_out, allowed_redirects - 1);

if (sock < 0)
error = sock;
}
else
error = HTTP_EPROTOCOL;
}
else
error = HTTP_EREDIRECT;

UrlFree(&curl);
}
else {
error = HTTP_EREDIRECT;
}
}

Free(location);
}
else
error = HTTP_ECONNECT;
Expand All @@ -84,8 +135,9 @@ I64 HttpOpenGet(U8* host, U16 port = 0, U8* path, I64* len_out) {
close(sock);
return error;
}
else
else {
return sock;
}
}

I64 HttpGet(U8* host, U16 port = 0, U8* path, U8** data_out = NULL, I64* len_out = NULL) {
Expand Down
2 changes: 0 additions & 2 deletions SnailNet/SnailLib.HC
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ I64 create_connection(U8* addr, U16 port) {
}

I64 recv(I64 sockfd, U8* buf, I64 len, I64 flags) {
I64 total = 0;

// This will be problematic for UDP
if (len > SNAIL_FRAME_SIZE)
len = SNAIL_FRAME_SIZE;
Expand Down
125 changes: 59 additions & 66 deletions SnailNet/Url.HC
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,80 @@

#include "::/Adam/Net/Http"

#define URL_EPARSE (-201)
#define URL_EPROTOCOL (-202)

class CUrl {
U8* protocol;
U8* host;
U16 port;
U8* path;
};

U0 UrlInit(CUrl* url) {
url->protocol = 0;
url->host = 0;
url->port = 0;
url->path = 0;
}
I64 UrlGet(U8* url, U8** data_out = NULL, I64* size_out = NULL) {
CUrl curl;
UrlInit(&curl);

I64 error = 0;

U0 UrlFree(CUrl* url) {
Free(url->protocol);
Free(url->host);
Free(url->path);
UrlInit(url);
if (UrlParse(url, &curl)) {
if (!StrCmp(curl.protocol, "http"))
error = HttpGet(curl.host, curl.port, curl.path, data_out, size_out);
else
error = URL_EPROTOCOL;
}
else
error = URL_EPARSE;

UrlFree(&curl);
return error;
}

Bool UrlParse(U8* url, CUrl* url_out) {
U8* colon = StrFirstOcc(url, ":");
U8* protosep = StrFind("//", url);
I64 UrlGetWithProgress(U8* url, U8** data_out, I64* size_out) {
CUrl curl;
UrlInit(&curl);

if (colon && colon < protosep) {
I64 len = colon - url;
url_out->protocol = MAlloc(len + 1);
MemCpy(url_out->protocol, url, len);
url_out->protocol[len] = 0;
I64 error = 0;
I64 size = 0;

url = colon + 1;
while (*url == '/')
url++;
}
else {
url_out->protocol = StrNew("http");
}
if (UrlParse(url, &curl)) {
if (!StrCmp(curl.protocol, "http")) {
I64 sock = HttpOpenGet(curl.host, curl.port, curl.path, &size);

I64 pos = 0;
if (sock > 0) {
U8* data = MAlloc(1 + size);
I64 total = 0;
I64 progress = 0;
"[$FG,3$";

while (url[pos]) {
if (url[pos] == ':' || url[pos] == '/') {
url_out->host = MAlloc(pos + 1);
MemCpy(url_out->host, url, pos);
url_out->host[pos] = 0;
while (total < size) {
I64 step = size - total;

if (url[pos] == ':') {
I64 port = 0;
U8* end = 0;
port = Str2I64(url + pos + 1, 10, &end);
if (step > 1024)
step = 1024;

url_out->port = port;
url_out->path = StrNew(end);
}
else {
url_out->path = StrNew(url + pos);
}
I64 got = recv(sock, data + total, step, 0);

return TRUE;
}
if (got <= 0) {
error = HTTP_EEOF;
break;
}

pos++;
}
total += got;

url_out->host = StrNew(url);
return TRUE;
}
I64 new_progress = (20 * total + size - 1) / size;
while (progress < new_progress) {
'' 0xfe;
progress++;
}
}

I64 UrlGet(U8* url, U8** data_out = NULL, I64* size_out = NULL) {
CUrl curl;
UrlInit(&curl);
close(sock);

I64 error = 0;
if (error) {
"$FG,4$x\n$FG$";
Free(data);
return error;
}

if (UrlParse(url, &curl)) {
if (!StrCmp(curl.protocol, "http"))
error = HttpGet(curl.host, curl.port, curl.path, data_out, size_out);
"$FG$]\n";
data[total] = 0;
*data_out = data;
*size_out = total;
}
else
error = sock;
}
else
error = URL_EPROTOCOL;
}
Expand Down
Loading

0 comments on commit d9d2c6b

Please sign in to comment.