1
0
Fork 0

terrasync.py: add support for the HTTPS protocol

- Instantiate an HTTPSConnection object when the URL scheme is 'https'.

- Clarify and simplify the initialization of HTTPSocketRequest and
  HTTPDownloadRequest:
    + clarify initialization of their 'callback' attribute (it's the
      method of the same name; make it clear that the base class
      constructor, namely HTTPGetCallback.__init__(), doesn't modify the
      'callback' attribute when an object of class HTTPSocketRequest or
      HTTPDownloadRequest is initialized);
    + HTTPDownloadRequest doesn't need access to the TerraSync object
      -> remove the corresponding instance attribute and constructor
         argument.

- Don't use super() when initializing HTTPDownloadRequest objects
  (see [1]).

[1] https://fuhm.net/super-harmful/
This commit is contained in:
Florent Rougon 2020-12-15 15:19:42 +01:00
parent 62cdd30810
commit e342a0f41e
2 changed files with 24 additions and 13 deletions

View file

@ -65,6 +65,10 @@ class NetworkError(TerraSyncPyException):
"""Exception raised when getting a network error even after retrying.""" """Exception raised when getting a network error even after retrying."""
ExceptionShortDescription = "Network error" ExceptionShortDescription = "Network error"
class UnsupportedURLScheme(TerraSyncPyException):
"""Exception raised when asked to handle an unsupported URL scheme."""
ExceptionShortDescription = "Unsupported URL scheme"
class RepoDataError(TerraSyncPyException): class RepoDataError(TerraSyncPyException):
""" """
Exception raised when getting invalid data from the TerraSync repository.""" Exception raised when getting invalid data from the TerraSync repository."""

View file

@ -25,18 +25,19 @@ import hashlib
import os import os
import re import re
import shutil import shutil
import ssl
import sys import sys
import time import time
import urllib import urllib
from urllib.parse import urlparse, urljoin from urllib.parse import urlparse, urljoin
from http.client import HTTPConnection, _CS_IDLE, HTTPException from http.client import HTTPConnection, HTTPSConnection, HTTPException
from os import listdir from os import listdir
from os.path import isfile, isdir, join from os.path import isfile, isdir, join
from . import dirindex from . import dirindex
from .exceptions import UserError, NetworkError, RepoDataError, \ from .exceptions import UserError, NetworkError, RepoDataError, \
InvalidDirIndexFile InvalidDirIndexFile, UnsupportedURLScheme
from .virtual_path import VirtualPath from .virtual_path import VirtualPath
@ -120,6 +121,7 @@ class HTTPGetCallback:
by HTTPGetter.get(). by HTTPGetter.get().
""" """
if callback is not None:
self.callback = callback self.callback = callback
self.src = src self.src = src
@ -130,7 +132,16 @@ class HTTPGetter:
self.maxPending = maxPending self.maxPending = maxPending
self.requests = [] self.requests = []
self.pendingRequests = [] self.pendingRequests = []
if self.parsedBaseUrl.scheme == "http":
self.httpConnection = HTTPConnection(self.parsedBaseUrl.netloc) self.httpConnection = HTTPConnection(self.parsedBaseUrl.netloc)
elif self.parsedBaseUrl.scheme == "https":
context = ssl.create_default_context()
self.httpConnection = HTTPSConnection(self.parsedBaseUrl.netloc,
context=context)
else:
raise UnsupportedURLScheme(self.parsedBaseUrl.scheme)
self.httpRequestHeaders = headers = {'Host':self.parsedBaseUrl.netloc,'Content-Length':0,'Connection':'Keep-Alive','User-Agent':'FlightGear terrasync.py'} self.httpRequestHeaders = headers = {'Host':self.parsedBaseUrl.netloc,'Content-Length':0,'Connection':'Keep-Alive','User-Agent':'FlightGear terrasync.py'}
def assemblePath(self, httpGetCallback): def assemblePath(self, httpGetCallback):
@ -151,7 +162,6 @@ class HTTPGetter:
return urljoin(baseUrl + '/', httpGetCallback.src.asRelative()) return urljoin(baseUrl + '/', httpGetCallback.src.asRelative())
def doGet(self, httpGetCallback): def doGet(self, httpGetCallback):
conn = self.httpConnection
pathOnServer = self.assemblePath(httpGetCallback) pathOnServer = self.assemblePath(httpGetCallback)
self.httpConnection.request("GET", pathOnServer, None, self.httpConnection.request("GET", pathOnServer, None,
self.httpRequestHeaders) self.httpRequestHeaders)
@ -183,10 +193,9 @@ class HTTPGetter:
class HTTPDownloadRequest(HTTPGetCallback): class HTTPDownloadRequest(HTTPGetCallback):
def __init__(self, terrasync, src, dst, callback = None ): def __init__(self, src, dst, callback=None):
"""Initialize an HTTPDownloadRequest instance. """Initialize an HTTPDownloadRequest instance.
terrasync -- a TerraSync instance
src -- a VirtualPath instance (corresponding to the path src -- a VirtualPath instance (corresponding to the path
on the server for which a GET request is to be on the server for which a GET request is to be
issued) issued)
@ -199,8 +208,7 @@ class HTTPDownloadRequest(HTTPGetCallback):
instance. Its return value is ignored. instance. Its return value is ignored.
""" """
super().__init__(src, self.callback) HTTPGetCallback.__init__(self, src, None)
self.terrasync = terrasync
self.dst = dst self.dst = dst
self.mycallback = callback self.mycallback = callback
@ -241,7 +249,7 @@ class HTTPSocketRequest(HTTPGetCallback):
(presumably a file) (presumably a file)
""" """
HTTPGetCallback.__init__(self, src, self.callback) HTTPGetCallback.__init__(self, src, None)
def callback(self, url, httpResponse): def callback(self, url, httpResponse):
# Same comment as for HTTPDownloadRequest.callback() # Same comment as for HTTPDownloadRequest.callback()
@ -511,7 +519,7 @@ class TerraSync:
removeDirectoryTree(self.target, localFullPath) removeDirectoryTree(self.target, localFullPath)
print("Downloading '{}'".format(virtualPath)) print("Downloading '{}'".format(virtualPath))
request = HTTPDownloadRequest(self, virtualPath, localFullPath) request = HTTPDownloadRequest(virtualPath, localFullPath)
self.httpGetter.get(request) self.httpGetter.get(request)
else: else:
self.abortCheckMode(failedCheckReason, virtualPath) self.abortCheckMode(failedCheckReason, virtualPath)
@ -548,8 +556,7 @@ class TerraSync:
if not os.path.exists(localFullPath): if not os.path.exists(localFullPath):
os.makedirs(localFullPath) os.makedirs(localFullPath)
request = HTTPDownloadRequest(self, request = HTTPDownloadRequest(virtualPath / ".dirindex",
virtualPath / ".dirindex",
localDirIndex, localDirIndex,
self.handleDirindexRequest) self.handleDirindexRequest)
self.httpGetter.get(request) self.httpGetter.get(request)