git-svn-id: http://svn.code.sf.net/p/netboot65/code@203 93682198-c243-4bdb-bd91-e943c89aac3b

This commit is contained in:
jonnosan 2009-10-16 11:18:05 +00:00
parent 5c52e6e9a6
commit deb01de4df
12 changed files with 1013 additions and 8 deletions

View File

@ -89,6 +89,9 @@
.import __SELF_MODIFIED_CODE_LOAD__
.import __SELF_MODIFIED_CODE_RUN__
.import __SELF_MODIFIED_CODE_SIZE__
.import __HTTP_VARS_LOAD__
.import __HTTP_VARS_RUN__
.import __HTTP_VARS_SIZE__
.import cfg_tftp_server
kipper_param_buffer = $6000
@ -130,6 +133,8 @@ cold_init:
jsr $ff5B ;init. VIC
cli ;KERNAL init. finished
jsr init_tod
warm_init:
;set some funky colours
@ -158,6 +163,14 @@ warm_init:
ldax #__SELF_MODIFIED_CODE_SIZE__
jsr copymem
;relocate the self-modifying code (if necessary)
ldax #__HTTP_VARS_LOAD__
stax copy_src
ldax #__HTTP_VARS_RUN__
stax copy_dest
ldax #__HTTP_VARS_SIZE__
jsr copymem
ldax #netboot65_msg
jsr print
ldax #init_msg+1
@ -718,6 +731,59 @@ exit_ping:
lda #$05 ;petscii for white text
jsr print_a
jmp main_menu
;init the Time-Of-Day clock - cribbed from http://codebase64.org/doku.php?id=base:initialize_tod_clock_on_all_platforms
init_tod:
sei
lda #0
sta $d011 ;Turn off display to disable badlines
sta $dc0e ;Set TOD Clock Frequency to 60Hz
sta $dc0f ;Enable Set-TOD-Clock
sta $dc0b ;Set TOD-Clock to 0 (hours)
sta $dc0a ;- (minutes)
sta $dc09 ;- (seconds)
sta $dc08 ;- (deciseconds)
lda $dc08 ;
@wait_raster:
cmp $dc08 ;Sync raster to TOD Clock Frequency
beq @wait_raster
ldx #0 ;Prep X and Y for 16 bit
ldy #0 ; counter operation
lda $dc08 ;Read deciseconds
@loop1:
inx ;2 -+
bne @loop2 ;2/3 | Do 16 bit count up on
iny ;2 | X(lo) and Y(hi) regs in a
jmp @loop3 ;3 | fixed cycle manner
@loop2:
nop ;2 |
nop ;2 -+
@loop3:
cmp $dc08 ;4 - Did 1 decisecond pass?
beq @loop1 ;3 - If not, loop-di-doop
;Each loop = 16 cycles
;If less than 118230 cycles passed, TOD is
;clocked at 60Hz. If 118230 or more cycles
;passed, TOD is clocked at 50Hz.
;It might be a good idea to account for a bit
;of slack and since every loop is 16 cycles,
;28*256 loops = 114688 cycles, which seems to be
;acceptable. That means we need to check for
;a Y value of 28.
cpy #28 ;Did 114688 cycles or less go by?
bcc @hertz_correct ;- Then we already have correct 60Hz $dc0e value
lda #$80 ;Otherwise, we need to set it to 50Hz
sta $dc0e
@hertz_correct:
lda #$1b ;Enable the display again
sta $d011
cli
rts
.rodata
netboot65_msg:

View File

@ -41,9 +41,9 @@ end
filebytes=File.open(filename,"rb").read
start_of_nb65_cart_image=filebytes.index("80NB65")
if start_of_nb65_cart_image.nil? then
puts "file '#{filename}' does not appear to be a netboot65 cartridge image"
start_of_kipper_cart_image=filebytes.index("80KIPPER")
if start_of_kipper_cart_image.nil? then
puts "file '#{filename}' does not appear to be a kipper cartridge image"
exit
end
@ -58,7 +58,7 @@ end
show_options
exit
end
option_offset=start_of_nb65_cart_image+offsets[0]-7
option_offset=start_of_kipper_cart_image+offsets[0]-7
option_length=offsets[1]
if option_length==6 then

View File

@ -7,7 +7,8 @@ MEMORY {
ROM: start = $8036, size = $3FCA, define = yes, file = %O;
RAM: start = $C010, size = $0fE0, define = yes;
RAM2: start = $0334, size = $CB, define = yes; #extra scratch area - Tape I/O buffer
RAM3: start = $0800, size = $7800, define = yes; #scratch area for apps embedded in cart to use
RAM3: start = $0200, size = $58, define = yes; #extra scratch area - Tape I/O buffer
RAM4: start = $0800, size = $7800, define = yes; #scratch area for apps embedded in cart to use
}
SEGMENTS {
@ -18,7 +19,8 @@ SEGMENTS {
DATA: load = ROM, run = RAM, type = rw, define = yes;
SELF_MODIFIED_CODE: load = ROM, run = RAM2, type = rw, define = yes;
BSS: load = RAM, type = bss;
APP_SCRATCH: load = RAM3, type = bss;
TCP_VARS: load = RAM2, type = bss;
APP_SCRATCH: load = RAM4, type = bss;
TCP_VARS: load = RAM2, type = bss;
HTTP_VARS: load=ROM, run = RAM3, type = rw,define = yes;
IP65ZP: load = IP65ZP, type = zp;
}

View File

@ -20,5 +20,6 @@ SEGMENTS {
IP65ZP: load = IP65ZP, type = zp, optional=yes;
EXEHDR: load = DISCARD, type = ro, optional=yes;
TCP_VARS: load = RAM, type = bss, optional=yes;
HTTP_VARS: load = RAM, type = bss, optional=yes;
}

View File

@ -45,6 +45,9 @@ KPR_PING_HOST EQU $32 ;inputs: AX points to destination IP addre
KPR_FILE_LOAD EQU $40 ;inputs: AX points to a file access parameter structure, outputs: none
KPR_HTTPD_START EQU $50 ;inputs: AX points to a routine to call for each inbound request, outputs: none
KPR_HTTPD_GET_VAR_VALUE EQU $52 ;inputs: A=variable to get value for ($01 to get method, $02 to get path)
KPR_PRINT_ASCIIZ EQU $80 ;inputs: AX=pointer to null terminated string to be printed to screen, outputs: none
KPR_PRINT_HEX EQU $81 ;inputs: A=byte digit to be displayed on screen as (zero padded) hex digit, outputs: none
KPR_PRINT_DOTTED_QUAD EQU $82 ;inputs: AX=pointer to 4 bytes that will be displayed as a decimal dotted quad (e.g. 192.168.1.1)

View File

@ -20,6 +20,8 @@ ETHOBJS= \
ip65.o \
printf.o \
debug.o \
http.o \
httpd.o \
dhcp.o \
dns.o \
dottedquad.o \

View File

@ -484,6 +484,21 @@ bne :+
rts
:
cpy #KPR_HTTPD_START
bne :+
.import httpd_start
jmp httpd_start
:
cpy #KPR_HTTPD_GET_VAR_VALUE
bne :+
.import http_get_value
jmp http_get_value
:
cpy #KPR_PING_HOST
.import icmp_echo_ip
.import icmp_ping

251
client/ip65/http.s Normal file
View File

@ -0,0 +1,251 @@
;routines for parsing a HTTP request
;to use - first call http_parse_request, then call http_get_value to get method name, path, and variable values
;NB - this routine uses the same buffer space and zero page locations as many other ip65 routines. so do not call
;other ip65 routines between the http_parse_request & http_get_value else odd things will happen.
.include "../inc/common.i"
.ifndef KPR_API_VERSION_NUMBER
.define EQU =
.include "../inc/kipper_constants.i"
.endif
.export http_parse_request
.export http_get_value
.importzp copy_src
.importzp copy_dest
.import output_buffer
;reuse the copy_src zero page var
string_ptr = copy_src
table_ptr=copy_dest
var_table=output_buffer
.bss
var_name: .res 1
hex_digit: .res 1
.code
;split a HTTP request into method (e.g. GET or POST), the path, and any querystring variables
;NB only the first letter in a variable name is significant. i.e. if a querystring contains variables 'a','alpha' & 'alabama', only the first one in will be retreivable.
;the method is stored in var $01
;the path is stored in var $02
;for example, parsing "GET /goober?a=foo&alpha=beta" would result in:
;value of A when calling http_get_value value returned by http_get_value
; #$01 "GET"
; #$02 "/goober"
; #'a' "foo"
; #'A' (error)
;inputs:
;AX = pointer to HTTP request
;outputs:
; none - but values can be retrieved through subsequent calls to http_get_value
http_parse_request:
stax string_ptr
ldax #var_table
stax table_ptr
lda #1 ;start of method
ldy #0
jsr put_byte
lda (string_ptr),y
cmp #'/'
beq @gopher
jsr @check_end_of_string
bcs @gopher
lda (string_ptr),y
@extract_method:
cmp #' '
beq @end_of_method
jsr @check_end_of_string
bcc :+
jmp @done
:
jsr put_byte
jsr get_next_byte_in_source
jmp @extract_method
@gopher:
jsr @output_end_of_method
lda #'/'
jmp @got_path_char
@output_end_of_method:
lda #0 ;end of method
jsr put_byte
lda #2 ;start of path
jmp put_byte
@end_of_method:
jsr @output_end_of_method
@extract_path:
jsr get_next_byte_in_source
jsr @check_end_of_string
bcs @done
cmp #'?'
beq @end_of_path
cmp #'&'
beq @end_of_path
@got_path_char:
jsr put_byte
jmp @extract_path
@end_of_path:
lda #0 ;end of path
jsr put_byte
@next_var:
jsr get_next_byte_in_source
jsr @check_end_of_string
bcs @done
jsr put_byte
@skip_to_equals:
jsr get_next_byte_in_source
jsr @check_end_of_string
bcs @done
cmp #'?'
beq @next_var
cmp #'&'
beq @next_var
cmp #'='
beq @got_var
jmp @skip_to_equals
@got_var:
jsr get_next_byte_in_source
jsr @check_end_of_string
bcs @done
cmp #'?'
beq @end_of_var
cmp #'&'
beq @end_of_var
cmp #'%'
beq @get_percent_encoded_byte
cmp #'+'
bne :+
lda #' '
:
@got_byte:
jsr put_byte
jmp @got_var
@end_of_var:
lda #0
jsr put_byte
jmp @next_var
@done:
lda #0
jsr put_byte
jsr put_byte
rts
@check_end_of_string:
cmp #0
beq @end_of_string
cmp #' '
beq @end_of_string
cmp #$0a
beq @end_of_string
cmp #$0d
beq @end_of_string
clc
rts
@end_of_string:
sec
rts
@get_percent_encoded_byte:
jsr get_next_byte_in_source
jsr parse_hex_digit
asl
asl
asl
asl
sta hex_digit
jsr get_next_byte_in_source
jsr parse_hex_digit
clc
adc hex_digit
jmp @got_byte
put_byte:
sta (table_ptr),y
inc table_ptr
bne :+
inc table_ptr+1
:
rts
;retrieve the value of a variable defined in the previously parsed HTTP request.
;inputs:
;A = variable to retrieve.
; to get the method (GET/POST/HEAD), pass A=$01.
; to get the path (everything between the method and the first '?'), pass A=$02.
;outputs:
; if variable exists in HTTP request, carry flag will be clear and AX points to value (null terminated string)
; if variable did not exist, carry flag will be set.
http_get_value:
sta var_name
ldax #var_table
stax string_ptr
ldy #0
lda (string_ptr),y
@check_next_var:
beq @end_of_vars
cmp var_name
beq @got_var
;not the var we want, so skip over till next byte
@skip_till_null_byte:
jsr get_next_byte_in_source
bne @skip_till_null_byte
jsr get_next_byte_in_source
bne @check_next_var
@end_of_vars:
sec
rts
@got_var:
jsr get_next_byte_in_source
ldax string_ptr
clc
rts
get_next_byte_in_source:
inc string_ptr
bne :+
inc string_ptr+1
:
lda (string_ptr),y
rts
parse_hex_digit:
cmp #$3A
bcs @not_digit
sec
sbc #$30
rts
@not_digit:
ora #$20 ;make lower case
sec
sbc #'a'-10
rts

370
client/ip65/httpd.s Normal file
View File

@ -0,0 +1,370 @@
;a simple HTTP server
;to use - call httpd_start with AX pointing at routine to call for each inbound page
;call httpd_stop to exit gracefully.
.include "../inc/common.i"
.ifndef KPR_API_VERSION_NUMBER
.define EQU =
.include "../inc/kipper_constants.i"
.endif
HTTPD_TIMEOUT_SECONDS=5 ;what's the maximum time we let 1 connection be open for?
.export httpd_start
.import http_parse_request
.import http_get_value
.import tcp_listen
.import tcp_callback
.import ip65_process
.import check_for_abort_key
.import ip65_error
.import print
.import copymem
.importzp copy_src
.importzp copy_dest
.import tcp_inbound_data_ptr
.import tcp_inbound_data_length
.import tcp_send_data_len
.import tcp_send
.import tcp_close
temp_ptr =copy_src
.segment "HTTP_VARS"
tcp_buffer_ptr: .res 2
httpd_buffer: .word $2000 ;by default, use a buffer at $2000 for storing inbound requests.
httpd_port_number: .word 80
connection_timeout_seconds: .byte 0
found_eol: .byte 0
connection_closed: .byte 0
output_buffer_length: .res 2
jump_to_callback:
jmp $ffff
get_next_byte:
lda $ffff
inc get_next_byte+1
bne @skip
inc get_next_byte+2
@skip:
rts
emit_a:
sta $ffff
inc emit_a+1
bne :+
inc emit_a+2
:
inc output_buffer_length
bne :+
inc output_buffer_length+1
lda output_buffer_length+1
cmp #2
bne :+
jmp send_buffer
:
rts
.code
;start a HTTP server
;this routine will stay in an endless loop that is broken only if user press the ABORT key (runstop on a c64)
;inputs:
;httpd_port_number=port number to listen on
;AX = pointer to routine to callback for each inbound HTTP request=
;set this to $0000 to use the default handler (which will look for requested files on the local disk).
;outputs:
; none
httpd_start:
stx jump_to_callback+2
bne @not_default_handler
ldax #default_httpd_handler
jmp httpd_start
@not_default_handler:
sta jump_to_callback+1
@listen:
jsr tcp_close
ldax httpd_buffer
stax tcp_buffer_ptr
ldax #http_callback
stax tcp_callback
ldax httpd_port_number
jsr tcp_listen
bcc @connect_ok
rts
@connect_ok:
lda #0
sta connection_closed
sta found_eol
clc
lda $dc09 ;time of day clock: seconds (in BCD)
sed
adc #HTTPD_TIMEOUT_SECONDS
cmp #$60
bcc @timeout_set
sec
sbc #$60
@timeout_set:
cld
sta connection_timeout_seconds
@main_polling_loop:
jsr ip65_process
jsr check_for_abort_key
bcc @no_abort
lda #KPR_ERROR_ABORTED_BY_USER
sta ip65_error
rts
@no_abort:
lda found_eol
bne @got_eol
lda $dc09 ;time of day clock: seconds
cmp connection_timeout_seconds
beq @connection_timed_out
lda connection_closed
beq @main_polling_loop
@connection_timed_out:
jmp @listen
@got_eol:
ldax httpd_buffer
jsr http_parse_request
jsr jump_to_callback ;call the handler to generate the response for this request.
;AX should now point at data to be sent
;Y should contain the content type/status code
bcs :+ ;carry is set if the callback routine already sent the response
jsr send_response
:
jmp @listen ;go listen for the next request
http_callback:
lda tcp_inbound_data_length+1
cmp #$ff
bne @not_eof
inc connection_closed
rts
@not_eof:
;copy this chunk to our input buffer
ldax tcp_buffer_ptr
stax copy_dest
ldax tcp_inbound_data_ptr
stax copy_src
ldax tcp_inbound_data_length
jsr copymem
;increment the pointer into the input buffer
clc
lda tcp_buffer_ptr
adc tcp_inbound_data_length
sta tcp_buffer_ptr
sta temp_ptr
lda tcp_buffer_ptr+1
adc tcp_inbound_data_length+1
sta tcp_buffer_ptr+1
sta temp_ptr+1
;put a null byte at the end (assumes we have set temp_ptr already)
lda #0
tay
sta (temp_ptr),y
;look for CR or LF in input
sta found_eol
ldax httpd_buffer
stax get_next_byte+1
@look_for_eol:
jsr get_next_byte
cmp #$0a
beq @found_eol
cmp #$0d
bne @not_eol
@found_eol:
inc found_eol
rts
@not_eol:
cmp #0
bne @look_for_eol
rts
default_httpd_handler:
lda #$02
jsr http_get_value
bcc @not_error
ldy #5
clc
rts
@not_error:
stax temp_ptr
ldy #1
lda (temp_ptr),y
bne @not_index
ldax #default_html
ldy #2
clc
rts
@not_index:
ldy #4
clc
rts
send_response:
stax get_next_byte+1
jsr reset_output_buffer
jsr send_header
@response_loop:
jsr get_next_byte
cmp #0
beq send_buffer
jsr emit_a
jmp @response_loop
reset_output_buffer:
ldax httpd_buffer
sta emit_a+1
stx emit_a+2
lda #0
sta output_buffer_length
sta output_buffer_length+1
rts
send_buffer:
ldax output_buffer_length
stax tcp_send_data_len
ldax httpd_buffer
jsr tcp_send
jmp reset_output_buffer
send_header:
;inputs: Y = header type
;$00 = no header (assume header sent already)
;$01 = 200 OK, 'text/text'
;$02 = 200 OK, 'text/html'
;$03 = 200 OK, 'application/octet-stream'
;$04 = 404 Not Found
;$05..$FF = 500 System Error
cpy #00
bne :+
rts
:
cpy #1
bne @not_text
jsr emit_ok_status_line_and_content_type
ldax #text_text
jsr emit_string
jmp @done
@not_text:
cpy #2
bne @not_html
jsr emit_ok_status_line_and_content_type
ldax #text_html
jsr emit_string
jmp @done
@not_html:
cpy #3
bne @not_binary
jsr emit_ok_status_line_and_content_type
ldax #application_octet_stream
jsr emit_string
jmp @done
@not_binary:
cpy #4
bne @not_404
ldax #http_version
jsr emit_string
ldax #status_not_found
jsr emit_string
jsr @done
ldax #status_not_found
jmp emit_string
@not_404:
ldax #http_version
jsr emit_string
ldax #status_system_error
jsr emit_string
jsr @done
ldax #status_system_error
jmp emit_string
@done:
ldax #end_of_header
jmp emit_string
emit_ok_status_line_and_content_type:
ldax #http_version
jsr emit_string
ldax #status_ok
jsr emit_string
ldax #content_type
jmp emit_string
emit_string:
stax temp_ptr
ldy #0
@next_byte:
lda (temp_ptr),y
beq @done
jsr emit_a
iny
bne @next_byte
@done:
rts
.rodata
default_html:
.byte "<h1>w00t!</h1><br>yadda yadda yadd!"
.byte 0
CR=$0D
LF=$0A
http_version:
.byte "HTTP/1.0 ",0
status_ok:
.byte "200 OK",CR,LF,0
status_not_found:
.byte "404 Not Found",CR,LF,0
status_system_error:
.byte "500 System Error",CR,LF,0
content_type:
.byte "Content-Type: ",0
text_text:
.byte "text/text",CR,LF,0
text_html:
.byte "text/html",CR,LF,0
application_octet_stream:
.byte "application/octet-stream",CR,LF,0
end_of_header:
.byte "Connection: Close",CR,LF
.byte "Server: Kipper_httpd/0.c64",CR,LF
.byte CR,LF,0

View File

@ -29,10 +29,13 @@ all: \
testdottedquad.pg2\
testdottedquad.prg\
test_tcp.prg \
test_httpd.prg \
test_parser.prg \
test_ping.prg \
test_sntp.prg \
test_get_url.prg \
test_parse_querystring.prg \
httpd_test.d64 \
# ip65test.dsk \
%.o: %.c
@ -59,7 +62,11 @@ test_ping.prg: test_ping.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg
%.pg2: %.o $(IP65LIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2bin.cfg
$(LD) -C ../cfg/a2bin.cfg -o $*.pg2 $(AFLAGS) $< $(IP65LIB) $(APPLE2PROGLIB)
httpd_test.d64: test_httpd.prg
cp test_httpd.prg autoexec.prg
ripxplore.rb --init CbmDos httpd_test.d64 -a autoexec.prg
ip65test.dsk: testdns.pg2 testdottedquad.pg2 testtftp.pg2
ripxplore.rb --init BeautifulBoot ip65test.dsk -a testdns.pg2 -t AppleBinary
ripxplore.rb ip65test.dsk -a testdns.pg2 -t AppleBinary

167
client/test/test_httpd.s Normal file
View File

@ -0,0 +1,167 @@
;test the "Kipper Kartridge API"
.ifndef KPR_API_VERSION_NUMBER
.define EQU =
.include "../inc/kipper_constants.i"
.endif
.include "../ip65/copymem.s"
; load A/X macro
.macro ldax arg
.if (.match (.left (1, arg), #)) ; immediate mode
lda #<(.right (.tcount (arg)-1, arg))
ldx #>(.right (.tcount (arg)-1, arg))
.else ; assume absolute or zero page
lda arg
ldx 1+(arg)
.endif
.endmacro
; store A/X macro
.macro stax arg
sta arg
stx 1+(arg)
.endmacro
print_a = $ffd2
.macro cout arg
lda arg
jsr print_a
.endmacro
.zeropage
temp_ptr: .res 2
.bss
kipper_param_buffer: .res $20
block_number: .res $0
.segment "STARTUP" ;this is what gets put at the start of the file on the C64
.word basicstub ; load address
.macro print arg
ldax arg
ldy #KPR_PRINT_ASCIIZ
jsr KPR_DISPATCH_VECTOR
.endmacro
.macro print_cr
lda #13
jsr print_a
.endmacro
.macro call arg
ldy arg
jsr KPR_DISPATCH_VECTOR
.endmacro
basicstub:
.word @nextline
.word 2003
.byte $9e
.byte <(((init / 1000) .mod 10) + $30)
.byte <(((init / 100 ) .mod 10) + $30)
.byte <(((init / 10 ) .mod 10) + $30)
.byte <(((init ) .mod 10) + $30)
.byte 0
@nextline:
.word 0
;look for KIPPER signature at location pointed at by AX
look_for_signature:
stax temp_ptr
ldy #5
@check_one_byte:
lda (temp_ptr),y
cmp kipper_signature,y
bne @bad_match
dey
bpl@check_one_byte
clc
rts
@bad_match:
sec
rts
init:
ldax #KPR_CART_SIGNATURE ;where signature should be in cartridge
jsr look_for_signature
bcc @found_kipper_signature
jmp kipper_signature_not_found
@found_kipper_signature:
print #initializing
ldy #KPR_INITIALIZE
jsr KPR_DISPATCH_VECTOR
bcc :+
print #failed
jsr print_errorcode
jmp bad_boot
:
print #ok
print_cr
call #KPR_PRINT_IP_CONFIG
ldax #$0000
call #KPR_HTTPD_START
jsr print_errorcode
rts
bad_boot:
print #press_a_key_to_continue
restart:
jsr get_key
jmp $fce2 ;do a cold start
print_errorcode:
print #error_code
call #KPR_GET_LAST_ERROR
call #KPR_PRINT_HEX
print_cr
rts
;use C64 Kernel ROM function to read a key
;inputs: none
;outputs: A contains ASCII value of key just pressed
get_key:
jsr $ffe4
cmp #0
beq get_key
rts
kipper_signature_not_found:
ldy #0
:
lda kipper_signature_not_found_message,y
beq restart
jsr print_a
iny
jmp :-
kipper_signature:
.byte "KIPPER" ; API signature
error_code:
.asciiz "ERROR CODE: $"
press_a_key_to_continue:
.byte "PRESS A KEY TO CONTINUE",13,0
failed:
.byte "FAILED ", 0
ok:
.byte "OK ", 0
kipper_signature_not_found_message:
.byte "NO KIPPER API FOUND",13,"PRESS ANY KEY TO RESET", 0
initializing:
.byte "INITIALIZING ",0

View File

@ -0,0 +1,121 @@
.include "../inc/common.i"
.include "../inc/commonprint.i"
.include "../inc/net.i"
.import print_a
.import get_key
.import cfg_get_configuration_ptr
.import ascii_to_native
.import http_parse_request
.import http_get_value
.bss
temp_ax: .res 2
.segment "STARTUP" ;this is what gets put at the start of the file on the C64
.word basicstub ; load address
basicstub:
.word @nextline
.word 2003
.byte $9e
.byte <(((init / 1000) .mod 10) + $30)
.byte <(((init / 100 ) .mod 10) + $30)
.byte <(((init / 10 ) .mod 10) + $30)
.byte <(((init ) .mod 10) + $30)
.byte 0
@nextline:
.word 0
init:
;switch to lower case charset
lda #23
sta $d018
ldax #query_1
jsr test_querystring
ldax #query_2
jsr test_querystring
ldax #query_3
jsr test_querystring
jsr get_key
ldax #query_4
jsr test_querystring
ldax #query_5
jsr test_querystring
ldax #query_6
jsr test_querystring
rts
test_querystring:
stax temp_ax
jsr print_ascii_as_native
jsr print_cr
ldax temp_ax
jsr http_parse_request
lda #1
jsr print_var
lda #2
jsr print_var
lda #'h'
jsr print_var
lda #'m'
jsr print_var
lda #'q'
jsr print_var
rts
print_var:
pha
cmp #1
beq @print_method
cmp #2
beq @print_path
jsr ascii_to_native
jsr print_a
@print_equals:
lda #'='
jsr print_a
pla
jsr http_get_value
bcc @found_var_value
lda #'?'
jsr print_a
jmp print_cr
@found_var_value:
jsr print_ascii_as_native
jmp print_cr
@print_path:
ldax #path
jmp @print_caption
@print_method:
ldax #method
@print_caption:
jsr print_ascii_as_native
jmp @print_equals
.rodata
path: .byte "path",0
method: .byte "method",0
query_1:
.byte "GET /?h=slack&m=goober+woober+woo%21+%3B+i+am+text HTTP/1.1",0
query_2:
.byte "POST /?h=slack&m=goober+woober+woo!+%3b+i+am+text",0
query_3:
.byte "GET /?handle=slack&message=goober+woober+woo%21+%3B+i+am+text+%0d%0a%21%40%23%24%25%5E%26%25%5D%5B%7B%7D& HTTP/1.1",0
query_4:
.byte "GET /this/is/a/long/q/path.html?q=foo",0
query_5:
.byte "/this/is/a/gopher_selector",0
query_6:
.byte $0d,$0a,0 ;this should also be a gopher path