Skip to content

Commit 5f949ba

Browse files
committed
added the next two steps of the http server
1 parent 3995e77 commit 5f949ba

8 files changed

Lines changed: 414 additions & 16 deletions

File tree

week-04/code/trigram.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
for i in range(61):
3636
infile.readline()
3737
# read the rest of the file into memory
38-
in_data = open(infilename, 'r').read()
38+
in_data = infile.read()
3939

4040
# Dictionary for trigram results:
4141
# The keys will be all the word pairs

week-05/code/code_summary.txt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
Folders:
2-
3-
Brian's: echo_server.py and echo_client.py work nice when run from dos command prompt. Echo client sends a "Hello, world" and gets it back from the server. print_time.py works as expected. When called from Safary with "http://localhost:8080/" as the URL, thirty_minute_webserver.py displays a list of the files in the folder as links, one per row, with thirty_minute_webserver.py as one of the links. When you click the link, the browser shows you the file (text, mostly, or the image in favicon.ico).
41

52
web: folder of resources that can be requested with the fourth, fifth and sixth server scripts.
63

74

8-
Files:
9-
10-
Chris's echo_client.py and echo_server.py work together to have the server return each thing the client sends and the client takes input from the user on what to send.
11-
5+
echo_client.py and echo_server.py work together to have the server return each thing the client sends and the client takes input from the user on what to send. YOU can start them each in its own console, and type things in the client console to see what happens.
6+
127
httpdate.py: Formats dates to HTTP 1.1 spec.
138

14-
http_serve1.py: Returns tiny_html.html without headers, which shows up fine in Safari. I couldn't figure out how to quit this from within the cmd window where I had run this.
9+
http_serve1.py: Returns tiny_html.html without headers, which shows up fine in Safari. NOTE: On Windows, ctrl+C won't quit the script while it is waiting for a reply. If you hit ctrl+C, then point the browser at it, it will quit. Or you can quit it by closing the console or killing the Python.exe process in taskmgr
1510

1611
http_serve2.py: Returns tiny_html.html with headers and also prints the first 120 characters of the response.
1712

18-
http_serve3.py: Same as previous but also prints the requested resource and querystring.
13+
http_serve3.py: Same as previous but also prints the requested resource and querystring. This requires the code to parse the request header.
1914

2015
http_serve4.py: Same as previous but instead of tiny_html.html, it returns a list of the files and folders in the web folder in plain text. Or if you point the url to the images subfolder of web (like: http://localhost:50000/images/) you get a list of the files in the images folder.
2116

@@ -30,3 +25,10 @@ Files:
3025
this_dir.html: Template HTML for a directory listing of the folders and files in the week-05\code\ directory.
3126

3227
tiny_html.html: File returned by the first three server scripts.
28+
29+
30+
Brian's Folder: Examples from previous version of this class (Brian is the previous teacher of this class):
31+
32+
echo_server.py and echo_client.py work nice when run from dos command prompt. Echo client sends a "Hello, world" and gets it back from the server. print_time.py works as expected. When called from Safari with "http://localhost:8080/" as the URL, thirty_minute_webserver.py displays a list of the files in the folder as links, one per row, with thirty_minute_webserver.py as one of the links. When you click the link, the browser shows you the file (text, mostly, or the image in favicon.ico).
33+
34+

week-05/code/http_serve4.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def format_dir_list(dir_list):
9797

9898
def get_file(URI):
9999
root_dir = 'web' # must be run from code dir...
100-
URI = URI.lstrip('/') #weird-- os.path.join does not like a leading slash
100+
URI = URI.lstrip('/') # os.path.join does not like a leading slash
101101
filename = os.path.join( root_dir, URI)
102102
print "path to file:", filename
103103
if os.path.isfile(filename):
@@ -107,8 +107,7 @@ def get_file(URI):
107107
print "it's a dir"
108108
return format_dir_list(os.listdir(filename)), 'txt'
109109
else:
110-
raise ValueError("there is nothing by that name")
111-
110+
raise ValueError("there is nothing by that name")
112111

113112
while True: # keep looking for new connections forever
114113
client, address = s.accept() # look for a connection

week-05/code/http_serve6.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,11 @@ def get_file(URI):
150150
print "received:", request
151151
URI = parse_request(request)
152152
print "URI requested is:", URI
153-
file_data, ext = get_file(URI)
154-
response = OK_response(file_data, ext)
153+
try:
154+
file_data, ext = get_file(URI)
155+
response = OK_response(file_data, ext)
156+
except ValueError:
157+
response = Error_response(URI)
155158
print "sending:"
156159
print response[:200]
157160
client.send(response)

week-05/code/http_serve7.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#!/usr/bin/env python
2+
3+
import socket
4+
import os
5+
6+
import httpdate
7+
8+
host = '' # listen on all connections (WiFi, etc)
9+
port = 50000
10+
backlog = 5 # how many connections can we stack up
11+
size = 1024 # number of bytes to receive at once
12+
13+
root_dir = 'web' # must be run from code dir...
14+
15+
print "point your browser to http://localhost:%i"%port
16+
17+
## create the socket
18+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
19+
# set an option to tell the OS to re-use the socket
20+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
21+
22+
# the bind makes it a server
23+
s.bind( (host,port) )
24+
s.listen(backlog)
25+
26+
html = open("tiny_html.html").read()
27+
28+
mime_types={}
29+
mime_types['html'] = "text/html"
30+
mime_types['htm'] = "text/html"
31+
mime_types['txt'] = "text/plain"
32+
mime_types['png'] = "image/png"
33+
mime_types['jpeg'] = "image/jpg"
34+
mime_types['jpg'] = "image/jpg"
35+
36+
def OK_response(entity, extension='html'):
37+
"""
38+
returns an HTTP response: header and entity in a string
39+
"""
40+
resp = []
41+
resp.append('HTTP/1.1 200 OK')
42+
resp.append(httpdate.httpdate_now())
43+
type = mime_types.get(extension, 'text/plain')
44+
resp.append( 'Content-Type: %s'%type )
45+
resp.append('Content-Length: %i'%len(entity))
46+
resp.append('')
47+
resp.append(entity)
48+
49+
return "\r\n".join(resp)
50+
51+
def Error_response(URI):
52+
"""
53+
returns an HTTP 404 Not Found Error response:
54+
55+
URI is the name of the entity not found
56+
"""
57+
resp = []
58+
resp.append('HTTP/1.1 404 Not Found')
59+
resp.append(httpdate.httpdate_now())
60+
resp.append('Content-Type: text/plain')
61+
62+
msg = "404 Error:\n %s \n not found"%( URI )
63+
64+
resp.append('Content-Length: %i'%( len(msg) ) )
65+
resp.append('')
66+
resp.append(msg)
67+
68+
return "\r\n".join(resp)
69+
70+
71+
def parse_request(request):
72+
"""
73+
parse an HTTP request
74+
75+
returns the URI asked for
76+
77+
note: minimal parsing -- only supprt GET
78+
79+
example:
80+
GET / HTTP/1.1
81+
Host: localhost:50000
82+
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0
83+
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
84+
Accept-Language: en-us,en;q=0.5
85+
Accept-Encoding: gzip, deflate
86+
Connection: keep-alive
87+
Cache-Control: max-age=0
88+
"""
89+
# first line should be the method line:
90+
lines = request.split("\r\n")
91+
92+
method, URI, protocol = lines[0].split()
93+
94+
# a bit of checking:
95+
if method.strip() != "GET":
96+
raise ValueError("I can only process a GET request")
97+
if protocol.split('/')[0] != "HTTP":
98+
raise ValueError("I can only process an HTTP request")
99+
100+
return URI
101+
102+
def format_dir_list(URI):
103+
"""
104+
format the contests of dir as HTML with links
105+
"""
106+
dir = os.path.join(root_dir, URI)
107+
names = os.listdir(dir)
108+
109+
dirs = [d for d in names if os.path.isdir(os.path.join(dir,d))]
110+
files = [d for d in names if os.path.isfile(os.path.join(dir,d))]
111+
112+
html =[]
113+
html.append("<http> <body>")
114+
html.append("<h2>%s</h2>"%URI)
115+
print "URI:", URI
116+
if URI: # don't need the parent dir at the root
117+
html.append('<a href="..">Parent</a>' )
118+
html.append("<h3>Directories:</h3>")
119+
html.append(" <ul>")
120+
for d in dirs:
121+
html.append(' <li> <a href="%s">%s </a></li>'%(os.path.join(URI,d), d))
122+
html.append(" </ul>")
123+
html.append("<h3>Files:</h3>")
124+
html.append(" <ul>")
125+
for f in files:
126+
html.append(' <li> <a href="%s"> %s </a> </li>'%(os.path.join(URI,f), f) )
127+
html.append(" </ul>")
128+
html.append("</body> </http>")
129+
return "\n".join(html)
130+
131+
def get_time_page():
132+
"""
133+
returns and html page with the current time in it
134+
"""
135+
time = httpdate.httpdate_now()
136+
html = "<html> <body> <h1> %s </h1> </body> </html>"%time
137+
return html
138+
139+
def get_file(URI):
140+
141+
URI = URI.strip('/') #weird-- os.path.join does not like a leading slash
142+
# check if this is the time server option
143+
if URI.lower() == "get_time":
144+
return get_time_page(), 'html'
145+
else:
146+
filename = os.path.join( root_dir, URI)
147+
if os.path.isfile(filename):
148+
contents = open(filename, 'rb').read()
149+
ext = os.path.splitext(filename)[1].strip('.')
150+
return contents, ext
151+
elif os.path.isdir(filename):
152+
return format_dir_list(URI), 'htm'
153+
else:
154+
raise ValueError("there is nothing by that name")
155+
156+
157+
while True: # keep looking for new connections forever
158+
client, address = s.accept() # look for a connection
159+
request = client.recv(size)
160+
if request: # if the connection was closed there would be no data
161+
print "received:", request
162+
URI = parse_request(request)
163+
try:
164+
file_data, ext = get_file(URI)
165+
response = OK_response(file_data, ext)
166+
except ValueError:
167+
response = Error_response(URI)
168+
client.send(response)
169+
client.close()
170+

0 commit comments

Comments
 (0)