2

I have the next python code:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os

PORT_NUMBER = 8080

#This class will handles any incoming request from
#the browser
class myHandler(BaseHTTPRequestHandler):

    store_path = os.path.dirname(os.path.realpath(__file__)) + '\copyFile'
    print store_path
    # handler for the GET requests
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        # Send the html message
        self.wfile.write("Hello World !")
        return

    # handeler for POST request
    def do_POST(self):
        length = self.headers['content-length']
        data = self.rfile.read(int(length))
        with open(self.store_path, 'w') as fh:
            fh.write(data.decode())

        self.send_response(200)

try:
    #Create a web server and define the handler to manage the
    #incoming request
    server = HTTPServer(('', PORT_NUMBER), myHandler)
    print 'Started httpserver on port ' , PORT_NUMBER

    #Wait forever for incoming htto requests
    server.serve_forever()

except KeyboardInterrupt:
    print '^C received, shutting down the web server'
server.socket.close()

I'm trying to make a simple python webserver to save files that is POSTed to a local path. I am sending the file to the server with curl with the following line: curl -F file="myfile.txt" http://localhost:8080

The result is not as i expected:

--------------------------e6929774a41d68c0

Content-Disposition: form-data; name="file"



myfile.txt

--------------------------e6929774a41d68c0--

What can i do to fix the problem?

I checked this link but it doesnt help :(

Community
  • 1
  • 1
Martin Rezyne
  • 445
  • 3
  • 9
  • 24
  • 1
    I think it's just the way you are using curl. Look at the curl man page to see what -F does for more details. But I believe you just need to do: `curl -F "file=@myfile.txt" http://localhost:8080`. The @ reads and sends the contents of the file rather than just the name of the file like your curl command was doing. – Stuart Robertson Mar 30 '15 at 15:46
  • Now it displays all the text from the file, but I have some extra stuff too: Content-Disposition, Content-Type and that thing with `-----` – Martin Rezyne Mar 30 '15 at 16:07

1 Answers1

2

Okay, so what is happening here is that you've started your HTTPServer which creates a thread that listens for incoming connections. When it gets a valid connection, it creates an instance of your request handler which will call the appropriate method based on the input from the incoming connection.

The BaseHTTPRequestHandler will process the incoming data behind the scenes and give you some useful variables to access the data. The data being sent in is retrieved from standard input. Because BaseHTTPRequestHandler is fairly basic it will only do so much for you. The raw data from this stream can be found in the self.rfile object. This is were you will find you query string, JSON or binary files.

Now you can write your own parser to retrieve this data, but that can be complicated and there are already modules out there that can help you with this. There is a standard Python module named cgi which can make this easier for you. You can find information about this module here.

What you need to do to retrieve your file is the following:

import cgi

...

class myHandler(BaseHTTPRequestHandler):

    ...

    def do_POST(self):
        form = cgi.FieldStorage(
                 fp=self.rfile,
                 headers=self.headers,
                 environ={"REQUEST_METHOD": "POST",
                          "CONTENT_TYPE": self.headers['Content-Type']})

         uploaded_file = form.getvalue("file")
         if uploaded_file:
             with open(self.store_path, "wb") as fh:
                 fh.write(uploaded_file.file.read())

        ...

The BaseHTTPRequestHandler doesn't actually parse the data in a POST for you, so we need to provide the FieldStorage object with the information it needs to be able to parse the data correctly. We need to provide it with the file that contains the raw data and the headers contained in the request. We also need to give it the environment with details about the request since BaseHTTPRequestHandler doesn't parse the POST these variables aren't added into the default environment which is why we are creating a dictionary of our own. I would consider taking a look at CGIHTTPServer which will encapsulate some of this behavior.

Once you create the form, we can use the 'safe' getter to retrieve our data. If the keyword is not there then this method will return None. You can also retrieve the data using something like:

try:
    uploaded_file = form['file']

except KeyError:
    # The 'file' parameter was missing.
    # Respond to the client with an error...
    ...

Both of these methods return either a FieldStorage or a MiniFieldStorage object. The details of these can be found in the link to the cgi module. But a killer feature in Python is the help method. E.g.

import cgi
help(cgi.FieldStorage)

This will list a man page giving all the details you need to know about the FieldStorage object.

As a side note, when building paths in Python you are best using os.path.join() to safely create a valid path for the system you are running under. So rather than having the line:

store_path = os.path.dirname(os.path.realpath(__file__)) + '\copyFile'

I would replace this with:

store_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'copyFile')
Stuart Robertson
  • 773
  • 7
  • 22