mirror of
https://github.com/bobbimanners/emailler.git
synced 2024-10-11 01:23:42 +00:00
git-svn-id: http://svn.code.sf.net/p/netboot65/code@203 93682198-c243-4bdb-bd91-e943c89aac3b
This commit is contained in:
parent
5c52e6e9a6
commit
deb01de4df
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -20,6 +20,8 @@ ETHOBJS= \
|
||||
ip65.o \
|
||||
printf.o \
|
||||
debug.o \
|
||||
http.o \
|
||||
httpd.o \
|
||||
dhcp.o \
|
||||
dns.o \
|
||||
dottedquad.o \
|
||||
|
@ -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
251
client/ip65/http.s
Normal 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
370
client/ip65/httpd.s
Normal 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
|
@ -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
167
client/test/test_httpd.s
Normal 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
|
||||
|
121
client/test/test_parse_querystring.s
Normal file
121
client/test/test_parse_querystring.s
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user