-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb_server.s
More file actions
213 lines (180 loc) · 4.46 KB
/
Copy pathweb_server.s
File metadata and controls
213 lines (180 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# Simple HTTP web server in x86-64 Linux assembly
# Supports concurrent GET and POST requests via fork
# GET : reads and returns file contents
# POST : writes request body to specified file
.global _start
.intel_syntax noprefix
.data
static_response: .ascii "HTTP/1.0 200 OK\r\n\r\n"
.text
_start:
# setup
socket:
mov rax, 41
mov rdi, 2 # AF_INET
mov rsi, 1 # SOCK_STREAM => TCP
mov rdx, 0
syscall
mov r8, rax # save socket FD
bind:
# Build sockaddr_in in the stack
sub rsp, 16
mov word ptr [rsp], 2 # AF_INET
mov word ptr [rsp+2], 0x5000 # port 80 in big endiannes
mov dword ptr [rsp+4], 0 # sin_addr = 0.0.0.0
mov qword ptr [rsp+8], 0 # sin_zero padding
mov rax, 49
mov rdi, r8 # listening socket FD
mov rsi, rsp
mov rdx, 16
syscall
listen:
mov rax, 50
mov rdi, r8 # listening socket FD
mov rsi, 0
syscall
# connection loop parent
accept:
mov rax, 43
mov rdi, r8 # listening socket FD
mov rsi, 0
mov rdx, 0
syscall
mov r9, rax # saves the new FD into r9
fork:
mov rax, 57
syscall
after_fork:
cmp rax, 0 # is process child or parent?
jne after_fork_parent
mov rax, 3
mov rdi, r8 # child process closes its listening socket
syscall
jmp read_request
after_fork_parent:
mov rax, 3
mov rdi, r9 # parent process closes the forked FD
syscall
jmp accept # parent process loops back to accept
# request handling child
read_request:
mov rax, 0
mov rdi, r9 # client FD
sub rsp, 4096 # make room on the stack for the request
mov rsi, rsp
mov rdx, 4096
syscall
mov r13, rax # save total bytes read for POST length calculation
check_method:
cmp byte ptr [rsp], 'G' # checks if first byte is G => get or not => post
je is_get
jmp is_post
is_get:
mov r15, 0 # 0 = GET
jmp parse_filepath
is_post:
mov r15, 1 # 1 = POST
jmp parse_filepath
# path parsing
parse_filepath:
lea rdi, [rsp+4] # 'GET ' is 4 bytes, 'POST ' is 5 bytes
add rdi, r15 # extra byte if POST
parse_filepath_loop:
cmp byte ptr [rdi], 0x20 # is the byte a space?
je found_filepath
inc rdi
jmp parse_filepath_loop
found_filepath:
mov byte ptr [rdi], 0 # null terminates instead of space
# now rsp+4+r15 is a valid null terminated path string
cmp r15, 0
je get_open
jmp post_open
# get handler
get_open:
mov rax, 2
lea rdi, [rsp+4]
add rdi, r15 # 0 but for consistency with post_open
mov rsi, 0
syscall
mov r10, rax # save open FD
get_read_file:
mov rax, 0
mov rdi, r10 # open FD
sub rsp, 4096
mov rsi, rsp
mov r12, rsp # save file buffer ptr
mov rdx, 4096
syscall
mov r13, rax # save the number of bytes read in r13
get_close_file:
mov rax, 3
mov rdi, r10 # open FD
syscall
get_write_static:
mov rax, 1
mov rdi, r9 # client FD
lea rsi, [rip+static_response] # pointer to static_response buffer
mov rdx, 19
syscall
get_write_file:
mov rax, 1
mov rdi, r9 # client FD
mov rsi, r12 # pointer to file content buffer
mov rdx, r13
syscall
jmp close_client
# post handler
post_open:
mov rax, 2
lea rdi, [rsp+4]
add rdi, r15
mov rsi, 65 # O_WRONLY | O_CREAT
mov rdx, 0777 # file permission octal, needed when O_CREAT is used
syscall
mov r10, rax # save open FD
post_find_body:
mov rdi, rsp
post_find_body_loop:
cmp byte ptr [rdi], 0x0d # \r
jne post_find_body_loop_next
cmp byte ptr [rdi+1], 0x0a # \n
jne post_find_body_loop_next
cmp byte ptr [rdi+2], 0x0d # \r
jne post_find_body_loop_next
cmp byte ptr [rdi+3], 0x0a # \n
jne post_find_body_loop_next
jmp post_found_body
post_find_body_loop_next:
inc rdi
jmp post_find_body_loop
post_found_body:
lea rsi, [rdi+4] # body starts right after '\r\n\r\n'
post_write_file:
mov rax, 1
mov rdi, r10 # opened file FD
# rsi still has body start ptr
mov rdx, rsi # body start pointer
sub rdx, rsp # header size
sub r13, rdx # total - header size = body length
mov rdx, r13 # body length into rdx
syscall
post_close_file:
mov rax, 3
mov rdi, r10 # file FD
syscall
post_write_static:
mov rax, 1
mov rdi, r9 # client FD
lea rsi, [rip+static_response] # pointer to static_response buffer
mov rdx, 19
syscall
# closing handling
close_client:
mov rax, 3
mov rdi, r9 # client FD
syscall
exit:
mov rax, 60
mov rdi, 0
syscall