4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the Revised BSD License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 Revised BSD License for more details.
12 Copyright 2016-2023 Game Maker 2k - https://github.com/GameMaker2k
13 Copyright 2016-2023 Kazuki Przyborowski - https://github.com/KazukiPrzyborowski
15 $FileInfo: pyhttpserv.py - Last Update: 10/5/2023 Ver. 2.0.2 RC 1 - Author: cooldude2k $
18 __program_name__
= "PyHTTPServer";
19 __program_alt_name__
= "PyHTTPServer";
20 __program_small_name__
= "httpserver";
21 __project__
= __program_name__
;
22 __project_url__
= "https://github.com/GameMaker2k/PyWWW-Get";
23 __version_info__
= (2, 0, 2, "RC 1", 1);
24 __version_date_info__
= (2023, 10, 5, "RC 1", 1);
25 __version_date__
= str(__version_date_info__
[0])+"."+str(__version_date_info__
[1]).zfill(2)+"."+str(__version_date_info__
[2]).zfill(2);
26 __revision__
= __version_info__
[3];
27 __revision_id__
= "$Id$";
28 if(__version_info__
[4] is not None):
29 __version_date_plusrc__
= __version_date__
+"-"+str(__version_date_info__
[4]);
30 if(__version_info__
[4] is None):
31 __version_date_plusrc__
= __version_date__
;
32 if(__version_info__
[3] is not None):
33 __version__
= str(__version_info__
[0])+"."+str(__version_info__
[1])+"."+str(__version_info__
[2])+" "+str(__version_info__
[3]);
34 if(__version_info__
[3] is None):
35 __version__
= str(__version_info__
[0])+"."+str(__version_info__
[1])+"."+str(__version_info__
[2]);
37 parser
= argparse
.ArgumentParser(description
="Simple HTTP Server in Python.", conflict_handler
="resolve", add_help
=True);
38 parser
.add_argument("-V", "--version", action
="version", version
=__program_name__
+" "+__version__
);
39 parser
.add_argument("-e", "--enablessl", action
="store_true", help="Enable SSL");
40 parser
.add_argument("-k", "--sslkeypem", default
=None, help="specify a custom user agent");
41 parser
.add_argument("-c", "--sslcertpem", default
=None, help="specify a custom referer, use if the video access");
42 parser
.add_argument("-p", "--servport", type=int, default
=8080, help="specify a file name for output");
43 getargs
= parser
.parse_args();
45 enablessl
= getargs
.enablessl
;
46 sslkeypem
= getargs
.sslkeypem
;
47 sslcertpem
= getargs
.sslcertpem
;
48 servport
= int(getargs
.servport
);
49 if(isinstance(servport
, int)):
50 if(servport
<1 or servport
>65535):
52 elif(isinstance(servport
, str)):
53 if(servport
.isnumeric()):
54 servport
= int(servport
);
55 if(servport
<1 or servport
>65535):
62 if(sslkeypem
is not None and
63 (not os
.path
.exists(sslkeypem
) or not os
.path
.isfile(sslkeypem
))):
66 if(sslcertpem
is not None and
67 (not os
.path
.exists(sslkeypem
) or not os
.path
.isfile(sslkeypem
))):
72 from BaseHTTPServer
import HTTPServer
;
73 from SimpleHTTPServer
import SimpleHTTPRequestHandler
;
74 from urlparse
import parse_qs
;
75 from Cookie
import SimpleCookie
77 from http
.server
import SimpleHTTPRequestHandler
, HTTPServer
;
78 from urllib
.parse
import parse_qs
;
79 from http
.cookies
import SimpleCookie
;
82 (sslkeypem
is not None and (os
.path
.exists(sslkeypem
) and os
.path
.isfile(sslkeypem
))) and
83 (sslcertpem
is not None and (os
.path
.exists(sslkeypem
) and os
.path
.isfile(sslkeypem
)))):
85 # HTTP/HTTPS Server Class
86 class CustomHTTPRequestHandler(SimpleHTTPRequestHandler
):
87 def display_info(self
):
88 # Setting headers for the response
89 self
.send_response(200);
90 self
.send_header('Content-type', 'text/plain');
91 # Set a sample cookie in the response;
92 self
.send_header('Set-Cookie', 'sample_cookie=sample_value; Path=/;');
94 # Displaying request method
95 response
= 'Method: {}\n'.format(self
.command
);
96 response
+= 'Path: {}\n'.format(self
.path
);
97 # Displaying all headers
98 headers_list
= ["{}: {}".format(key
.title(), self
.headers
[key
]) for key
in self
.headers
];
99 response
+= '\nHeaders:\n' + '\n'.join(headers_list
) + '\n';
100 # Extract and display cookies from headers
101 if 'Cookie' in self
.headers
:
102 response
+= '\nCookies:\n';
103 cookies
= SimpleCookie(self
.headers
['Cookie']);
104 for key
, morsel
in cookies
.items():
105 response
+= '{}: {}\n'.format(key
, morsel
.value
);
106 # Displaying GET parameters (if any)
107 if self
.command
== 'GET':
108 query
= self
.path
.split('?', 1)[-1];
109 params
= parse_qs(query
);
111 response
+= '\nGET Parameters:\n';
112 for key
, values
in params
.items():
113 response
+= '{}: {}\n'.format(key
, ', '.join(values
));
114 # Sending the response
115 self
.wfile
.write(response
.encode('utf-8'));
121 if 'Transfer-Encoding' in self
.headers
and self
.headers
['Transfer-Encoding'] == 'chunked':
124 chunk_size_line
= self
.rfile
.readline().decode('utf-8');
125 chunk_size
= int(chunk_size_line
, 16);
127 self
.rfile
.readline();
129 chunk_data
= self
.rfile
.read(chunk_size
).decode('utf-8');
130 post_data
+= chunk_data
;
131 self
.rfile
.readline();
133 content_length
= int(self
.headers
['Content-Length']);
134 post_data
= self
.rfile
.read(content_length
).decode('utf-8');
135 params
= parse_qs(post_data
);
136 response
= 'POST Parameters:\n';
137 for key
, values
in params
.items():
138 response
+= '{}: {}\n'.format(key
, ', '.join(values
));
139 self
.send_response(200);
140 self
.send_header('Content-type', 'text/plain');
141 self
.send_header('Set-Cookie', 'sample_cookie=sample_value; Path=/;');
143 self
.wfile
.write(response
.encode('utf-8'));
144 # Start Server Forever
145 if __name__
== "__main__":
146 server_address
= ('', int(servport
));
147 httpd
= HTTPServer(server_address
, CustomHTTPRequestHandler
);
148 if(enablessl
and sslkeypem
is not None and sslcertpem
is not None):
149 httpd
.socket
= ssl
.wrap_socket (httpd
.socket
,
150 keyfile
=sslkeypem
, certfile
=sslcertpem
, server_side
=True);
152 print("Server started at https://localhost:"+str(servport
));
154 print("Server started at http://localhost:"+str(servport
));
155 httpd
.serve_forever();