Add and use code to parse URLs specifying the resource.

This commit is contained in:
Stephen Heumann 2018-07-30 21:35:45 -05:00
parent ef272cb998
commit 28a0b1be19
13 changed files with 353 additions and 56 deletions

View File

@ -7,7 +7,14 @@
Boolean DoLookupName(Session *sess) {
dnrBuffer dnrInfo;
TCPIPDNRNameToIP(sess->domainName, &dnrInfo);
if (TCPIPValidateIPString(sess->hostName)) {
cvtRec cvtInfo;
TCPIPConvertIPToHex(&cvtInfo, sess->hostName);
sess->ipAddr = cvtInfo.cvtIPAddress;
return TRUE;
}
TCPIPDNRNameToIP(sess->hostName, &dnrInfo);
if (toolerror())
return FALSE;
@ -22,6 +29,9 @@ Boolean DoLookupName(Session *sess) {
sess->ipAddr = dnrInfo.DNRIPaddress;
return TRUE;
} else {
if (dnrInfo.DNRstatus == DNR_Pending) {
TCPIPCancelDNR(&dnrInfo);
}
return FALSE;
}
}

6
http.c
View File

@ -7,14 +7,14 @@
#include "session.h"
#include "http.h"
Boolean BuildHTTPRequest(Session *sess, char *resourceStr, char *hostStr) {
Boolean BuildHTTPRequest(Session *sess, char *resourceStr) {
int sizeNeeded = 0;
int rangeOffset;
int round = 0;
do {
sizeNeeded = snprintf(sess->httpRequest, sizeNeeded,
"GET %s HTTP/1.1\r\n"
"GET /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: GSRemoteDisk/0.1\r\n"
"Accept-Encoding: identity\r\n"
@ -23,7 +23,7 @@ Boolean BuildHTTPRequest(Session *sess, char *resourceStr, char *hostStr) {
"Range: bytes=%n1234567890-1234567890\r\n"
"\r\n",
resourceStr,
hostStr,
sess->hostName+1,
&rangeOffset);
if (sizeNeeded <= 0) {

2
http.h
View File

@ -4,7 +4,7 @@
#include <types.h>
#include "session.h"
Boolean BuildHTTPRequest(Session *sess, char *resourceStr, char *hostStr);
Boolean BuildHTTPRequest(Session *sess, char *resourceStr);
void UpdateRequestRange(Session *sess, unsigned long start, unsigned long end);
#endif

85
main.c
View File

@ -5,8 +5,10 @@
#include <locator.h>
#include <misctool.h>
#include <memory.h>
#include <orca.h>
#include "http.h"
#include "session.h"
#include "seturl.h"
#include "hostname.h"
#define buffTypePointer 0x0000 /* For TCPIPReadTCP() */
@ -21,38 +23,48 @@ http://ia800505.us.archive.org/16/items/a2gs_System_1.0_1986_Apple_FW/System_1.0
static char delimitStr[] = "\p\r\n\r\n";
int main(void) {
char *defaultURL = "http://ia800505.us.archive.org/16/items/a2gs_System_1.0_1986_Apple_FW/System_1.0_1986_Apple_FW.2mg";
int main(int argc, char **argv) {
TLStartUp();
LoadOneTool(54,0x200);
TCPIPStartUp();
TCPIPConnect(NULL);
if (TCPIPGetConnectStatus() == FALSE) {
TCPIPConnect(NULL);
if (toolerror())
goto exit;
}
Session sess;
FILE *f = fopen("out", "wb");
Session sess = {0};
char *url = (argc > 1) ? argv[1] : defaultURL;
BuildHTTPRequest(&sess, "/16/items/a2gs_System_1.0_1986_Apple_FW/System_1.0_1986_Apple_FW.2mg", "ia800505.us.archive.org");
fputs(sess.httpRequest, f);
UpdateRequestRange(&sess, 0, 511);
fputs(sess.httpRequest, f);
strcpy(sess.domainName, "\pia800505.us.archive.org");
Boolean result = DoLookupName(&sess);
if (result) {
printf("IP = %lu.%lu.%lu.%lu\n",
sess.ipAddr & 0xFF,
(sess.ipAddr >> 8) & 0xFF,
(sess.ipAddr >> 16) & 0xFF,
(sess.ipAddr >> 24));
} else {
printf("Address lookup failed\n");
enum SetURLResult result = SetURL(&sess, url, TRUE, FALSE);
if (result != SETURL_SUCCESSFUL) {
printf("SetURL error %i\n", (int)result);
goto exit;
}
sess.port = 80;
unsigned long startByte = 0;
if (argc > 2) {
startByte = strtoul(argv[2], NULL, 0);
}
UpdateRequestRange(&sess, startByte, startByte + 511);
printf("Request:\n");
printf("=========\n");
int i;
for (i = 0; sess.httpRequest[i] != '\0'; i++) {
char ch = sess.httpRequest[i];
if (ch != '\r')
putchar(ch);
}
printf("=========\n");
printf("\n", i);
int err;
if ((err = StartTCPConnection(&sess)) != 0) {
@ -61,18 +73,20 @@ int main(void) {
}
TCPIPWriteTCP(sess.ipid, sess.httpRequest, strlen(sess.httpRequest), TRUE, FALSE);
LongWord startTime = GetTick();
while (GetTick() - startTime < 3*60) {
//printf("polling\n");
TCPIPPoll();
}
rlrBuff rlrBuff;
TCPIPReadLineTCP(sess.ipid, (void*)((LongWord)delimitStr | 0x80000000),
buffTypeNewHandle, (Ref)NULL,
0xFFFFFF, &rlrBuff);
rlrBuff rlrBuff = {0};
Word tcpError;
do {
TCPIPPoll();
tcpError = TCPIPReadLineTCP(sess.ipid,
(void*)((LongWord)delimitStr | 0x80000000),
buffTypeNewHandle, (Ref)NULL,
0xFFFFFF, &rlrBuff);
if (tcpError || toolerror()) {
printf("tcpError = %u, toolerror = %u\n", tcpError, toolerror());
break;
}
} while (rlrBuff.rlrBuffCount == 0);
printf("Response:\n");
printf("=========\n");
@ -81,11 +95,8 @@ int main(void) {
if (ch != '\r')
putchar(ch);
}
//printf("%s\n", *(rlrBuff.rlrBuffHandle));
printf("=========\n");
printf("Response headers handle size = %lu \n", GetHandleSize(rlrBuff.rlrBuffHandle));
printf("Reported response size = %lu \n", rlrBuff.rlrBuffCount);
printf("Response size = %lu\n", rlrBuff.rlrBuffCount);
EndTCPConnection(&sess);

View File

@ -25,8 +25,8 @@ typedef struct Session {
LongWord ipAddr;
Word port;
/* Domain name of host (p-string; empty string for host specified by IP) */
char domainName[256];
/* Domain name or IP address of host (p-string, but also null-terminated) */
char hostName[257];
/* Time (GetTick) of last DNS lookup */
LongWord dnsTime;
} Session;

95
seturl.c Normal file
View File

@ -0,0 +1,95 @@
#include <types.h>
#include <errno.h>
#include "session.h"
#include "urlparser.h"
#include "strcasecmp.h"
#include "hostname.h"
#include "http.h"
#include "tcpconnection.h"
#include "seturl.h"
#define DEFAULT_HTTP_PORT 80
/* Limit to make sure sizes stay within the range of 16-bit values */
#define MAX_URL_LENGTH 30000
enum SetURLResult
SetURL(Session *sess, char *url, Boolean permissive, Boolean partialOK) {
if (strlen(url) > MAX_URL_LENGTH) {
return URL_TOO_LONG;
}
for(unsigned int i = 0; url[i] != '\0'; i++) {
if (url[i] <= ' ' && url[i] >= 0) {
return INVALID_CHARACTER_IN_URL;
}
}
URLParts urlParts = ParseURL(url);
if (urlParts.errorFound)
return BAD_URL_SYNTAX;
if (urlParts.scheme == NULL) {
if (permissive) {
urlParts.scheme = "http";
} else {
return BAD_URL_SYNTAX;
}
} else if (strcasecmp(urlParts.scheme, "http") != 0) {
return UNSUPPORTED_URL_SCHEME;
}
if (urlParts.username != NULL || urlParts.password != NULL) {
return AUTHENTICATION_NOT_SUPPORTED;
}
if (urlParts.fragment != NULL) {
return FRAGMENT_NOT_SUPPORTED;
}
unsigned long portNum;
char *endPtr;
if (urlParts.port == NULL || *urlParts.port == '\0') {
portNum = DEFAULT_HTTP_PORT;
} else {
errno = 0;
portNum = strtoul(urlParts.port, &endPtr, 10);
if (errno || *endPtr != '\0' || portNum > 0xFFFF) {
return INVALID_PORT_NUMBER;
}
}
sess->port = portNum;
if (urlParts.host == NULL) {
if (!partialOK || sess->hostName[0] == 0) {
return NO_HOST_SPECIFIED;
}
} else if (*urlParts.host == '\0') {
return NO_HOST_SPECIFIED;
} else if (*urlParts.host == '[') {
return IPV6_NOT_SUPPORTED;
} else {
size_t len;
if ((len = strlen(urlParts.host)) > 255) {
return HOSTNAME_TOO_LONG;
}
strcpy(&sess->hostName[1], urlParts.host);
sess->hostName[0] = len;
if (!DoLookupName(sess)) {
return NAME_LOOKUP_FAILED;
}
}
if (!BuildHTTPRequest(sess, urlParts.path)) {
return OUT_OF_MEMORY;
}
/* End any existing TCP connection to old URL */
EndTCPConnection(sess);
return SETURL_SUCCESSFUL;
}

23
seturl.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef SETURL_H
#define SETURL_H
enum SetURLResult {
SETURL_SUCCESSFUL = 0,
URL_TOO_LONG,
INVALID_CHARACTER_IN_URL,
BAD_URL_SYNTAX,
UNSUPPORTED_URL_SCHEME,
AUTHENTICATION_NOT_SUPPORTED,
FRAGMENT_NOT_SUPPORTED,
INVALID_PORT_NUMBER,
NO_HOST_SPECIFIED,
IPV6_NOT_SUPPORTED,
HOSTNAME_TOO_LONG,
NAME_LOOKUP_FAILED,
OUT_OF_MEMORY
};
enum SetURLResult
SetURL(Session *sess, char *url, Boolean permissive, Boolean partialOK);
#endif

View File

@ -5,12 +5,23 @@
#include <stddef.h>
#include <ctype.h>
int strcasecmp(const char *s1, const char *s2)
{
while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) {
s1++;
s2++;
}
return (int)*s1 - (int)*s2;
}
int strncasecmp(const char *s1, const char *s2, size_t n)
{
if (n == 0)
return 0;
while (n > 1 && *s1 != 0 && tolower(*s1) == tolower(*s2)) {
while (n > 1 && *s1 != '\0' && tolower(*s1) == tolower(*s2)) {
s1++;
s2++;
n--;

9
strcasecmp.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef STRCASECMP_H
#define STRCASECMP_H
#include <stddef.h>
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
#endif

View File

@ -1,6 +0,0 @@
#ifndef STRNCASECMP_H
#define STRNCASECMP_H
int strncasecmp(const char *s1, const char *s2, size_t n);
#endif

View File

@ -20,11 +20,8 @@ Word StartTCPConnection(Session *sess) {
srBuff mySRBuff;
LongWord initialTime;
if (TCPIPGetConnectStatus() == FALSE) {
TCPIPConnect(NULL);
if (toolerror())
return aspNetworkErr;
}
/* End any existing TCP connection */
EndTCPConnection(sess);
sess->ipid =
TCPIPLogin(userid(), sess->ipAddr, sess->port, 0, 0x40);

122
urlparser.c Normal file
View File

@ -0,0 +1,122 @@
#include "urlparser.h"
#include <string.h>
/*
* Parse the URL and break it up into its component parts.
*
* This handles http URLs and other schemes with the same syntax.
*
* It can also handle relative URLs containing an absolute-path reference
* (i.e. starting with /) and URL-like addresses without the scheme prefix.
* In these cases, the portions of the URL not provided will be NULL.
*
* This modifies the original string passed in, breaking it up into components.
*/
URLParts ParseURL(char *url) {
char *sep, sep2;
URLParts urlParts = {0};
sep = strrchr(url, '#');
if (sep) {
*sep = '\0';
urlParts.fragment = sep + 1;
}
/* Detect relative URL (absolute-path reference only) */
if (url[0] == '/') {
if (url[1] != '/') {
url++;
goto pathPart;
} else {
urlParts.errorFound = 1;
return urlParts;
}
}
sep = strchr(url, ':');
if (sep) {
urlParts.scheme = url;
*sep = '\0';
url = sep + 1;
}
if (urlParts.scheme != NULL) {
if (strncmp(url, "//", 2) == 0) {
url += 2;
} else {
urlParts.errorFound = 1;
return urlParts;
}
}
urlParts.path = strchr(url, '/');
if (urlParts.path == NULL) {
urlParts.path = "";
} else {
*urlParts.path = '\0';
urlParts.path++;
}
sep = strchr(url, '@');
if (sep) {
*sep = '\0';
urlParts.username = url;
urlParts.password = strchr(url, ':');
if (urlParts.password != NULL) {
*urlParts.password = '\0';
urlParts.password++;
}
url = sep + 1;
}
urlParts.host = url;
/* Handle IPv6 address syntax */
if (*url == '[') {
sep = strchr(url, ']');
if (sep) {
url = sep + 1;
} else {
urlParts.errorFound = 1;
return urlParts;
}
}
sep = strchr(url, ':');
if (sep) {
*sep = '\0';
urlParts.port = sep + 1;
}
pathPart:
return urlParts;
}
#ifdef URLPARSER_TEST
#include <stdio.h>
int main(int argc, char **argv)
{
URLParts urlParts;
if (argc < 2)
return 1;
urlParts = ParseURL(argv[1]);
printf("scheme: %s\n", urlParts.scheme ? urlParts.scheme : "(NULL)");
printf("username: %s\n", urlParts.username ? urlParts.username : "(NULL)");
printf("password: %s\n", urlParts.password ? urlParts.password : "(NULL)");
printf("host: %s\n", urlParts.host ? urlParts.host : "(NULL)");
printf("port: %s\n", urlParts.port ? urlParts.port : "(NULL)");
printf("path: %s\n", urlParts.path ? urlParts.path : "(NULL)");
printf("fragment: %s\n", urlParts.fragment ? urlParts.fragment : "(NULL)");
if (urlParts.errorFound) {
printf("Error found\n");
}
}
#endif

25
urlparser.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef URLPARSER_H
#define URLPARSER_H
#ifdef __ORCAC__
# include <types.h>
#else
typedef _Bool Boolean;
#endif
typedef struct URLParts {
char *scheme;
char *username;
char *password;
char *host;
char *port;
char *path; /* Omits leading '/'. Includes query, if any. */
char *fragment;
Boolean errorFound;
} URLParts;
URLParts ParseURL(char *url);
#endif