#!/usr/bin/env python3
import io
import os
import urllib.parse
import pycurl

# Before you use this program, create a test file to be posted.

# For 1GB file:
# dd if=/dev/random of=test.dat bs=1048576 count=1024

# For 8GB file:
# dd if=/dev/random of=test.dat bs=1048576 count=8192
TEST_FILE="test.dat"

# For windows: well, I just used some iso files for testing...



TEST_SITE='http://httpbin.org/post'                # Plain http test
#TEST_SITE='https://httpbin.org/post'              # https test with good cert
#TEST_SITE='https://office2cable.dyndns.org:49160' # my tornadoweb based server with self signed cert

CHECK_CERT=False # set flag to force checking of certificates.

TEST_CERT=None # Filename where the CA cert should be loaded from.
# You can extract with: " openssl s_client -connect httpbin.org:443 -showcerts "
#TEST_CERT="some.crt.pem"




class Test:
    USER_AGENT = "pycurl bug test"

    def __init__(self):
        self.percentfunc = None

    def create_curl(self, url, server_crt, percentfunc):
        curl = pycurl.Curl()
        curl.setopt(pycurl.URL, url)
        curl.setopt(pycurl.USERAGENT, self.USER_AGENT)
        if server_crt:
            if CHECK_CERT:
                curl.setopt(pycurl.SSL_VERIFYPEER, 1)
                curl.setopt(pycurl.SSL_VERIFYHOST, 2)
            else:
                curl.setopt(pycurl.SSL_VERIFYPEER, 0)
                curl.setopt(pycurl.SSL_VERIFYHOST, 0)
            curl.setopt(pycurl.CAINFO, server_crt)
        else:
            curl.setopt(pycurl.SSL_VERIFYPEER, 0)
            curl.setopt(pycurl.SSL_VERIFYHOST, 0)

        self.percent_up, self.percent_down = 0.0, 0.0
        self.percentfunc = percentfunc
        curl.setopt(curl.NOPROGRESS, 0)
        curl.setopt(curl.PROGRESSFUNCTION, self._progress)

        return curl


    @classmethod
    def _perform(cls, curl):
        e = io.BytesIO()
        curl.setopt(curl.WRITEFUNCTION, e.write)
        curl.perform()
        status = curl.getinfo(pycurl.HTTP_CODE)
        curl.close()
        if status != 200:
            raise Exception("%s %s"%(status, repr(e.getvalue())))
        else:
            return e.getvalue()


    def _progress(self, download_t, download_d, upload_t, upload_d):
        if upload_t:
            percent_up = round(100.0 * upload_d / upload_t, 1)
        else:
            percent_up = 0.0
        if download_t:
            percent_down = round(100.0 * download_d / download_t, 1)
        else:
            percent_down = 0.0
        if percent_down != self.percent_down or percent_up != self.percent_up:
            self.percent_up = percent_up
            self.percent_down = percent_down
            if self.percentfunc:
                self.percentfunc(percent_up, percent_down)


    def post(self, server_url, getparams, postvalues, files=None, percentfunc=None, server_crt=None):
        c = self.create_curl(
            server_url+"?"+urllib.parse.urlencode(getparams),
            server_crt,
            percentfunc
        )
        c.setopt(c. POST, 1)
        filevalues = []
        if files:
            for fname, fpath in files:
                filevalues.append((fname, (
                    c.FORM_FILENAME, os.path.split(fpath)[1],
                    c.FORM_FILE, fpath,
                    # c.FORM_CONTENTTYPE,"application/octet-stream"
                )))
        # print(postvalues+filevalues)
        c.setopt(c.HTTPPOST, postvalues+filevalues)
        return self._perform(c)

# Very simple example progress function.
_last = -1, -1
def my_percentfunc(percent_up, percent_down):
    global _last
    _new = (percent_up, percent_down)
    if _new != _last:
        print ("Up: %.2f%%\tDown: %.2f%%"%_new)
        _last = _new

test = Test()
test.post(
    server_url=TEST_SITE,
    getparams='',
    postvalues=[],
    files=[
        (os.path.split(TEST_FILE)[0],TEST_FILE)
    ],
    percentfunc=my_percentfunc,
    server_crt=TEST_CERT
)
