text: #!/usr/bin/env python3
  # coding: utf-8
  # Copyright 2016 Abram Hindle, https://github.com/tywtyw2002, and https://github.com/treedust
  # 
  # Copyright 2020 Dylan Alcock 
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  # 
  #     http://www.apache.org/licenses/LICENSE-2.0
  # 
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  # Do not use urllib's HTTP GET and POST mechanisms.
  # Write your own HTTP GET and POST
  # The point is to understand what you have to send and get experience with it
  
  import sys
  import socket
  import re
  # you may use urllib to encode data appropriately
  import urllib.parse
  
  def help():
      print("httpclient.py [GET/POST] [URL]\n")
  
  
  class HTTPResponse(object):
      def __init__(self, code=200, body=""):
          self.code = code
          self.body = body
  
  
  class HTTPClient(object):
      #def get_host_port(self,url):
  
      def connect(self, host, port):
          self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          self.socket.connect((host, port))
          return None
  
      # Gets the code from the response headers
      def get_code(self, data):
          code = int(data.split(" ")[1])
          return code
  
      # Gets the headers from the response header 
      def get_headers(self,data):
          array_response = data.split("\r\n\r\n")
          headers = array_response[0]
          return headers
  
      # Gets the body from the response header
      def get_body(self, data):
          array_response = data.split('\r\n\r\n')
          body = array_response[1]
          return body
      
      def sendall(self, data):
          self.socket.sendall(data.encode('utf-8'))
          
      def close(self):
          self.socket.close()
  
      # read everything from the socket
      def recvall(self, sock):
          buffer = bytearray()
          done = False
          while not done:
              part = sock.recv(1024)
              if (part):
                  buffer.extend(part)
              else:
                  done = not part
          return buffer.decode('utf-8')
  
      def GET(self, url, args=None):
          code = 500
          body = ""
          
          #Get parts of the url
          parseResult = urllib.parse.urlparse(url)
          host = parseResult.hostname
          port = parseResult.port
          scheme = parseResult.scheme
          path = parseResult.path
          query = parseResult.query
          
          #if port specified use that otherwise connect to port 80
          if (port):
              self.connect(host,port)
          else:
              self.connect(host, 80)
          
          if not (path):
              path = "/"
          
          # add query arguments if needed
          if (query):
              args_to_get = "?" + query
              if (args):
                  args_to_get += "&" + urllib.parse.urlencode(args)             
          else:
              args_to_get = ""
              if (args):
                  args_to_get += "?" + urllib.parse.urlencode(args) 
          
          try:
              # Reference: https://stackoverflow.com/questions/6686261/what-at-the-bare-minimum-is-required-for-an-http-request
              self.sendall("GET "+ path + args_to_get + " HTTP/1.1\r\nHost: " + 
                        host +"\r\nConnection: close\r\nAccept: */*\r\n\r\n")
              
          except socket.error:
              print("Send Failed")
              sys.exit()
          
          response = self.recvall(self.socket)
          
          header = self.get_headers(response)
          code = self.get_code(response)
          body = self.get_body(response)
              
          #print(body)     
          
          self.close()        
          return HTTPResponse(code, body)
  
      def POST(self, url, args=None):
          code = 500
          body = ""
          
          #Get parts of the url
          parseResult = urllib.parse.urlparse(url)
          host = parseResult.hostname
          port = parseResult.port
          scheme = parseResult.scheme
          path = parseResult.path
          query = parseResult.query
          #fragment = parseResult.fragment
          
          #if port specified use that otherwise connect to port 80
          if (port):
              self.connect(host,port)
          else:
              self.connect(host, 80)
          
          if not (path):
              path = "/"
          
          if (query):
              query = "?" + query     
          
          # add query arguments if needed
          args_to_post = ""
          if (args):
              args_to_post = urllib.parse.urlencode(args)               
          
          try:
              #Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
              self.sendall("POST " + path + query + " HTTP/1.1\r\n" +
              "Host: "+host+"\r\n" +
              "Content-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n" +
              "Content-Length: "+str(len(args_to_post))+"\r\n" +
              "Connection: close\r\n\r\n" + 
              args_to_post)
          
          except socket.error:
              print("Send Failed")
              sys.exit()
              
          response = self.recvall(self.socket)
          
          header = self.get_headers(response)
          code = self.get_code(response)
          body = self.get_body(response)       
          
          #print(body)   
          
          self.close()        
          
          return HTTPResponse(code, body)
  
      def command(self, url, command="GET", args=None):
          if (command == "POST"):
              return self.POST( url, args )
          else:
              return self.GET( url, args )
      
  if __name__ == "__main__":
      client = HTTPClient()
      command = "GET"
      if (len(sys.argv) <= 1):
          help()
          sys.exit(1)
      elif (len(sys.argv) == 3):
          print(client.command( sys.argv[2], sys.argv[1] ))
      else:
          print(client.command( sys.argv[1] ))
  