Search code examples
pythoncgipython-3.5httpserverbasehttprequesthandler

my http server got post request including file, how to forward to external URL using POST method too


I have a problem, and I searched a lot but none of codes here do my request

I'm running python local server using http.server - BaseHTTPRequestHandler

here is my code

def run_http():
    port=80
    server_address = ('', port)
    httpd = ThreadingHTTPServer(server_address, serverClass)

    # print('HTTP server running on port %s'% port)
    httpd.serve_forever()

class serverClass(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_GET(self):
        self._set_headers()

        if self.path == '/':
            with open("static\\index.html", 'r') as f:
                res = f.read()
            self.wfile.write(res.encode('utf-8'))

        elif self.path == '/favicon.ico':
            with open("static\\favicon.ico", 'rb') as f:
                res = f.read()
            self.wfile.write(res)
        
        else:
            ...


    def do_HEAD(self):
        self._set_headers()
        
    def do_POST(self):
        # content_length = int(self.headers['Content-Length'])
        # post_data = self.rfile.read(content_length)
        # <= here I need to forward the post request to another URL _POST_URL
        # The post request I received may include file and may be not, so I need to forward the post request as it is

I tried some codes for example:

ctype, pdict = cgi.parse_header(self.headers['content-type'])
pdict['boundary'] = bytes(pdict['boundary'], "utf-8")
if ctype == 'multipart/form-data':
    fields = cgi.parse_multipart(self.rfile, pdict)
    field_file = {'file':(fields.get('file'), "multipart/form-data")}
    fields.pop('file')
    r = requests.post(_POST_URL+'/in.php', files = field_file, data = fields)

note: I know that the file will be with post name file That code works, but the problem is I don't sent the file type or the file name, and I cannot got it really. Am I in the right way, or I should use more efficient codes


Solution

  • Ok I used cgi.FieldStorage

    and here is the code if somebody may interesed;

    def do_POST(self):
        form = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'] })
        
        post_data = {}
        for field in form:
            if field != 'file':
                post_data[field] = form.getvalue(field)
    
        # print(post_data)
        try:
            fileitem = form['file']
            if fileitem.filename:
                fn = os.path.basename(fileitem.filename)
                open('./tmp/' + fn, 'wb').write(fileitem.file.read())
                data_files = {'file' : open('./tmp/' + fn, 'rb')}
            # print(data_files)
            r = requests.post(_POST_URL, data = post_data, files = data_files)
        except:
            r = requests.post(_POST_URL, data = post_data)
        
        res = r.text
    
        try:
            data_files = None
            os.remove('./tmp/' + fn)
        except:
            pass
        self._set_headers()
        self.wfile.write(res.encode('utf-8'))
    

    This code is working for me, I don't know if there is a better way to do that!