Error response

Receiving files over HTTP with Python

It’s often very useful to be able to quickly send files over a network. One quick way to do this is to stand up a temporary HTTP server to send files. This can be done with Python’s http.server module:

$ python -m http.server Serving HTTP on 0.0.0.0 port 8000 . 127.0.0.1 - - [01/Nov/2016 22:44:19] "GET / HTTP/1.1" 200 - 

Note: In earlier versions of Python (2.x), the module is called SimpleHTTPServer .

Sending files the other way

In the example above files are pulled via a GET request. Unfortunately Python’s server implementation does not respond to PUT requests:

$ curl -X PUT --upload-file text.txt http://localhost:8000      

Error response

Error code: 501

Message: Unsupported method ('PUT').

Error code explanation: HTTPStatus.NOT_IMPLEMENTED - Server does not support this operation.

It is however fairly easy to extend the server implementation to add the missing method. The script below implements the do_PUT method:

#!/usr/bin/env python """Extend Python's built in HTTP server to save files curl or wget can be used to send files with options similar to the following curl -X PUT --upload-file somefile.txt http://localhost:8000 wget -O- --method=PUT --body-file=somefile.txt http://localhost:8000/somefile.txt __Note__: curl automatically appends the filename onto the end of the URL so the path can be omitted. """ import os try: import http.server as server except ImportError: # Handle Python 2.x import SimpleHTTPServer as server class HTTPRequestHandler(server.SimpleHTTPRequestHandler): """Extend SimpleHTTPRequestHandler to handle PUT requests""" def do_PUT(self): """Save a file following a HTTP PUT request""" filename = os.path.basename(self.path) # Don't overwrite files if os.path.exists(filename): self.send_response(409, 'Conflict') self.end_headers() reply_body = '"%s" already exists\n' % filename self.wfile.write(reply_body.encode('utf-8')) return file_length = int(self.headers['Content-Length']) with open(filename, 'wb') as output_file: output_file.write(self.rfile.read(file_length)) self.send_response(201, 'Created') self.end_headers() reply_body = 'Saved "%s"\n' % filename self.wfile.write(reply_body.encode('utf-8')) if __name__ == '__main__': server.test(HandlerClass=HTTPRequestHandler) 

Running the script

The script above should work out of the box with either Python 2 or Python 3. Once it’s downloaded cd to the directory you want to upload files to and run it:

$ mkdir upload $ cd upload/ $ python /tmp/http_put_server.py Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) . 

Files can then be uploaded to the directory using curl or wget :

$ curl -X PUT --upload-file test.txt http://localhost:8000 Saved "test.txt" 

A quick note on security

The script above will blindly accept files without authentication, and no encryption is used in transit. For transferring files quickly across a private network this should be OK. However exposing the web server over the Internet is almost certainly a terrible idea!

Copyright © 2021 Floating Octothorpe. Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 License.

Источник

Transferring Files Using Python’s Built-in HTTP Server

Python Http Transfer Featured

The need to transfer files over a network is one that arises often. GNU/Linux systems support multiple protocols and tools for doing so, some of which are designed for somewhat permanent file sharing (such as SMB, AFP, and NFS), while others such as Secure Copy (SCP) are used for quick manual and scripted file transfers. Among these is the HyperText Transfer Protocol (HTTP), the versatile and ubiquitous protocol on which the World Wide Web relies.

Python, which is included by default in most Linux distributions, provides simple HTTP servers through the “SimpleHTTPServer” and “http.server” modules. The former is found in the Python 2 Standard Library, while the latter is included in Python 3. These lightweight HTTP servers require no separate installation and can be started instantly with a single command.

Installing Python

Your system most likely includes at least one Python version, but if that’s not the case, install Python 3 using your native package manager.

For example, on Debian and Ubuntu:

sudo apt update sudo apt install -y python3

Starting the HTTP Server

Take note of the IP address used by the sending machine.

Python Http Transfer Ip Address

Find out which Python version is installed with the following commands:

python --version python3 --version

On the same machine, change your working directory to the one containing the files you’re transferring. Be aware of the fact that the entire contents of your current working directory may be accessible to anyone on your network (or the Internet if the sending machine has a public IP address), while the Python HTTP server is running.

You can now start the HTTP server. For Python 2.x, use the SimpleHTTPServer module:

python -m SimpleHTTPServer

Or http.server in the case of Python 3.x:

Both variations listen on port 8000 by default, though you can explicitly specify a different port number after the module name.

python -m SimpleHTTPServer [port] python3 -m http.server [port]

Note: root privileges are required if you choose a port under 1024.

Downloading Your Files

On the receiving machine, you can use any HTTP client to download your files. If you’re using a graphical environment, a browser is often more convenient than command line utilities. Simply browse to http://IP_ADDRESS:8000, where “IP_ADDRESS” is the IP address of the sending computer, and click on the desired files to download them.

Python Http Transfer Browser

Alternatively, you can use Wget or cURL to fetch your files. You should already have one or both of them installed. If neither are, we suggest installing Wget, as it is more user friendly and supports downloading whole directories.

For Fedora and RHEL/CentOS 8:

Using Wget

To download a single file with Wget, simply invoke Wget followed by the URL of the file you want to download.

wget http://IP_ADDRESS:8000/filename

Python Http Transfer Wget

You can also use Wget to recursively download the whole directory by adding the -r command-line flag.

wget -r http://IP_ADDRESS:8000/

Python Http Transfer Wget Recursive

Using cURL

By default, curl tries to print file contents to your terminal. So to save the file instead, specify a filename with the -o flag.

curl http://IP_ADDRESS:8000/filename -o filename

Python Http Transfer Curl

Conclusion

The HTTP functionality in Python’s standard library supplies a basic yet fast and convenient way of transferring files, perfect for some scenarios. But keep in mind that because this is plain HTTP with neither encryption nor authentication, you should be careful to not expose sensitive files.

Karl Wakim is a technical author and Linux systems administrator.

Our latest tutorials delivered straight to your inbox

Источник

# Python HTTP Server

Running this command serves the files of the current directory at port 9000 .

If no argument is provided as port number then server will run on default port 8000 .

The -m flag will search sys.path for the corresponding .py file to run as a module.

If you want to only serve on localhost you’ll need to write a custom Python program such as:

import sys import BaseHTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler HandlerClass = SimpleHTTPRequestHandler ServerClass = BaseHTTPServer.HTTPServer Protocol = "HTTP/1.0" if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 server_address = ('127.0.0.1', port) HandlerClass.protocol_version = Protocol httpd = ServerClass(server_address, HandlerClass) sa = httpd.socket.getsockname() print "Serving HTTP on", sa[0], "port", sa[1], ". " httpd.serve_forever() 

# Serving files

Assuming you have the following directory of files:

enter image description here

You can setup a web server to serve these files as follows:

import SimpleHTTPServer import SocketServer PORT = 8000 handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = SocketServer.TCPServer(("localhost", PORT), handler) print "Serving files at port <>".format(PORT) httpd.serve_forever() 
import http.server import socketserver PORT = 8000 handler = http.server.SimpleHTTPRequestHandler httpd = socketserver.TCPServer(("", PORT), handler) print("serving at port", PORT) httpd.serve_forever() 

The SocketServer module provides the classes and functionalities to setup a network server.

SocketServer ‘s TCPServer class sets up a server using the TCP protocol. The constructor accepts a tuple representing the address of the server (i.e. the IP address and port) and the class that handles the server requests.

The SimpleHTTPRequestHandler class of the SimpleHTTPServer module allows the files at the current directory to be served.

Save the script at the same directory and run it.

python -m SimpleHTTPServer 8000

The ‘-m’ flag will search ‘sys.path’ for the corresponding ‘.py’ file to run as a module.

(opens new window) in the browser, it will give you the following:

enter image description here

# Programmatic API of SimpleHTTPServer

What happens when we execute python -m SimpleHTTPServer 9000 ?

To answer this question we should understand the construct of SimpleHTTPServer (https://hg.python.org/cpython/file/2.7/Lib/SimpleHTTPServer.py)

Firstly, Python invokes the SimpleHTTPServer module with 9000 as an argument. Now observing the SimpleHTTPServer code,

def test(HandlerClass = SimpleHTTPRequestHandler, ServerClass = BaseHTTPServer.HTTPServer): BaseHTTPServer.test(HandlerClass, ServerClass) if __name__ == '__main__': test() 

The test function is invoked following request handlers and ServerClass. Now BaseHTTPServer.test is invoked

def test(HandlerClass = BaseHTTPRequestHandler, ServerClass = HTTPServer, protocol="HTTP/1.0"): """Test the HTTP request handler class. This runs an HTTP server on port 8000 (or the first command line argument). """ if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 server_address = ('', port) HandlerClass.protocol_version = protocol httpd = ServerClass(server_address, HandlerClass) sa = httpd.socket.getsockname() print "Serving HTTP on", sa[0], "port", sa[1], ". " httpd.serve_forever() 

Hence here the port number, which the user passed as argument is parsed and is bound to the host address. Further basic steps of socket programming with given port and protocol is carried out. Finally socket server is initiated.

This is a basic overview of inheritance from SocketServer class to other classes:

 +------------+ | BaseServer | +------------+ | v +-----------+ +------------------+ | TCPServer |---|---|---|---|---|---|---|---|---|---->| UnixStreamServer | +-----------+ +------------------+ | v +-----------+ +--------------------+ | UDPServer |---|---|---|---|---|---|---|---|---|---->| UnixDatagramServer | +-----------+ +--------------------+ 

(opens new window) are useful for finding further information.

# Basic handling of GET, POST, PUT using BaseHTTPRequestHandler

# from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer # python2 from http.server import BaseHTTPRequestHandler, HTTPServer # python3 class HandleRequests(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() self.wfile.write("received get request") def do_POST(self): '''Reads post request body''' self._set_headers() content_len = int(self.headers.getheader('content-length', 0)) post_body = self.rfile.read(content_len) self.wfile.write("received post request:
<>"
.format(post_body)) def do_PUT(self): self.do_POST() host = '' port = 80 HTTPServer((host, port), HandleRequests).serve_forever()

Example output using curl :

$ curl http://localhost/ received get request% $ curl -X POST http://localhost/ received post request:br>% $ curl -X PUT http://localhost/ received post request:br>% $ echo 'hello world' | curl --data-binary @- http://localhost/ received post request:br>hello world 

Источник

Читайте также:  Javascript events select options
Оцените статью