새소식

Programming/python

[python] 파일 업로딩용 http 서버 예제

  • -

기록용으로 남깁니다.

윈도우 서버에서 파일 업로딩이 급할 때 쓸 수 있는 http file server 라는 프로그램이 있습니다.

문제는 이 프로그램이 공유기 상의 포트포워딩을 사용하는 환경에서 잘 동작하지 않습니다. 제공되는 웹페이지에 직접 들어가서 하나 하나 업로드하는 것은 가능하지만 클라이언트 쪽에서 curl 등을 통해 자동 업로드 하는 데에는 문제가 있었습니다. 공유기의 DMZ 기능을 쓸 수 있는 상황도 아닙니다.

인증이 필요없이 잠깐 열었다 닫는 파일 업로딩 용도이고, cli 상에서 실행 가능하여 자동화할 수 있어야 하며, 파일 이름을 변경할 수 있는 기능(원본 aa.png 를 1111-aa.png 로 변경)까지 제공되야 하고, 공유기 환경에서도 동작해야하는데, 그 기능들을 모두 만족하는 프로그램을 찾기가 쉽지 않았습니다.

급하게 찾아보다 보니까 nodejs 기반의 서버도 있고 파이썬의 http.server, 1, 2, 3도 있는데 원하는대로 동작하지 않았습니다. 옵션이 문제인가 해서 curl 도 찾아보고 했지만 생각처럼 동작하지 않았네요.

구글링하다가 발견한 글을 보니 위의 파이썬 http.server 를 받아 그 안에 put 핸들러를 구현해서 업로드가 가능하다는 글을 봤습니다.

관련 내용을 실행해보니 잘 실행되는데 curl 옵션이 동작하지 않더군요

다만, wget 으로도 동작하고 저장할 파일명을 지정할 수 있어서 이 방식으로 급한대로 사용했습니다.

아래 소스를 적당히 httpserver.py 로 저장하고 서버(파일 저장되는 곳)에서 python3 httpserver.py 로 실행합니다.

#!/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)

클라이언트 쪽에서는 wget 으로 접근하면 됩니다.

wget -O- --method=PUT --body-file=/home/pi/image/2022-01-01_00-00-00.png http://2.2.2.2:8888/001-2022-01-01_00-00-00.png

ps: 나중에 찾아보니 파이썬 기반 이런 프로그램도 있네요 테스트는 못해봤습니다..

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.