def _checkUserAgent( self, request ): request.is_hydrus_user_agent = False if request.requestHeaders.hasHeader( 'User-Agent' ): user_agent_texts = request.requestHeaders.getRawHeaders( 'User-Agent' ) user_agent_text = user_agent_texts[0] try: user_agents = user_agent_text.split( ' ' ) except: return # crazy user agent string, so just assume not a hydrus client for user_agent in user_agents: if '/' in user_agent: ( client, network_version ) = user_agent.split( '/', 1 ) if client == 'hydrus': request.is_hydrus_user_agent = True network_version = int( network_version ) if network_version == HC.NETWORK_VERSION: return else: if network_version < HC.NETWORK_VERSION: message = 'Your client is out of date; please download the latest release.' else: message = 'This server is out of date; please ask its admin to update to the latest release.' raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! This server\'s network version is ' + str( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + str( network_version ) + '! ' + message )
def CheckHydrusVersion(service_key, service_type, response_headers): service_string = HC.service_string_lookup[service_type] if 'server' not in response_headers or service_string not in response_headers[ 'server']: HC.app.Write( 'service_updates', { service_key: [ HC.ServiceUpdate(HC.SERVICE_UPDATE_ACCOUNT, HC.GetUnknownAccount()) ] }) raise HydrusExceptions.WrongServiceTypeException('Target was not a ' + service_string + '!') server_header = response_headers['server'] (service_string_gumpf, network_version) = server_header.split('/') network_version = int(network_version) if network_version != HC.NETWORK_VERSION: if network_version > HC.NETWORK_VERSION: message = 'Your client is out of date; please download the latest release.' else: message = 'The server is out of date; please ask its admin to update to the latest release.' raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! The server\'s network version was ' + u(network_version) + ', whereas your client\'s is ' + u(HC.NETWORK_VERSION) + '! ' + message)
def _CheckHydrusVersion(self, service_type, response): service_string = HC.service_string_lookup[service_type] headers = response.headers if 'server' not in headers or service_string not in headers['server']: raise HydrusExceptions.WrongServiceTypeException( 'Target was not a ' + service_string + '!') server_header = headers['server'] (service_string_gumpf, network_version) = server_header.split('/') network_version = int(network_version) if network_version != HC.NETWORK_VERSION: if network_version > HC.NETWORK_VERSION: message = 'Your client is out of date; please download the latest release.' else: message = 'The server is out of date; please ask its admin to update to the latest release.' raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! The server\'s network version was ' + str(network_version) + ', whereas your client\'s is ' + str(HC.NETWORK_VERSION) + '! ' + message)
def _check_network_version( self, network_version ): if network_version != HC.NETWORK_VERSION: if network_version < HC.NETWORK_VERSION: message = 'Your client is out of date; please download the latest release.' else: message = 'This server is out of date; please ask its admin to update to the latest release.' message = 'Network version mismatch! This server\'s network version is ' + HC.u( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + HC.u( network_version ) + '! ' + message raise HydrusExceptions.NetworkVersionException( message )
def Request( self, method, path_and_query, request_headers, body, report_hooks = None, temp_path = None ): if report_hooks is None: report_hooks = [] if method == HC.GET: method_string = 'GET' elif method == HC.POST: method_string = 'POST' if 'User-Agent' not in request_headers: request_headers[ 'User-Agent' ] = 'hydrus/' + str( HC.NETWORK_VERSION ) path_and_query = HydrusData.ToByteString( path_and_query ) request_headers = { str( k ) : str( v ) for ( k, v ) in request_headers.items() } response = self._GetResponse( method_string, path_and_query, request_headers, body ) ( parsed_response, size_of_response ) = self._ReadResponse( response, report_hooks, temp_path ) response_headers = { k : v for ( k, v ) in response.getheaders() if k != 'set-cookie' } cookies = self._ParseCookies( response.getheader( 'set-cookie' ) ) self._last_request_time = HydrusData.GetNow() if response.status == 200: return ( parsed_response, None, size_of_response, response_headers, cookies ) elif response.status in ( 301, 302, 303, 307 ): location = response.getheader( 'Location' ) if location is None: raise Exception( 'Received an invalid redirection response.' ) else: url = location if ', ' in url: url = url.split( ', ' )[0] elif ' ' in url: # some booru is giving daft redirect responses HydrusData.Print( url ) url = urllib.quote( HydrusData.ToByteString( url ), safe = '/?=&' ) HydrusData.Print( url ) if not url.startswith( self._scheme ): # assume it is like 'index.php' or '/index.php', rather than 'http://blah.com/index.php' if url.startswith( '/' ): slash_sep = '' else: slash_sep = '/' url = self._scheme + '://' + self._host + slash_sep + url if response.status in ( 301, 307 ): # 301: moved permanently, repeat request # 307: moved temporarily, repeat request redirect_info = ( method, url ) elif response.status in ( 302, 303 ): # 302: moved temporarily, repeat request (except everyone treats it like 303 for no good f*****g reason) # 303: thanks, now go here with GET redirect_info = ( HC.GET, url ) return ( parsed_response, redirect_info, size_of_response, response_headers, cookies ) elif response.status == 304: raise HydrusExceptions.NotModifiedException() else: if response.status == 401: raise HydrusExceptions.PermissionException( parsed_response ) elif response.status == 403: raise HydrusExceptions.ForbiddenException( parsed_response ) elif response.status == 404: raise HydrusExceptions.NotFoundException( parsed_response ) elif response.status == 419: raise HydrusExceptions.SessionException( parsed_response ) elif response.status == 426: raise HydrusExceptions.NetworkVersionException( parsed_response ) elif response.status in ( 500, 501, 502, 503 ): server_header = response.getheader( 'Server' ) if server_header is not None and 'hydrus' in server_header: hydrus_service = True else: hydrus_service = False if response.status == 503 and hydrus_service: raise HydrusExceptions.ServerBusyException( 'Server is busy, please try again later.' ) else: raise Exception( parsed_response ) else: raise Exception( parsed_response )
def _ParseResponse( self, response, report_hooks ): server_header = response.getheader( 'Server' ) if server_header is not None and 'hydrus' in server_header: hydrus_service = True else: hydrus_service = False content_length = response.getheader( 'Content-Length' ) if content_length is not None: content_length = int( content_length ) for hook in report_hooks: hook( content_length, 0 ) data = '' for block in HydrusPaths.ReadFileLikeAsBlocks( response ): if HydrusGlobals.model_shutdown: raise HydrusExceptions.ShutdownException( 'Application is shutting down!' ) data += block if content_length is not None: for hook in report_hooks: hook( content_length, len( data ) ) if len( data ) > content_length: raise Exception( 'Response was longer than suggested!' ) size_of_response = len( data ) content_type = response.getheader( 'Content-Type' ) if content_type is None: parsed_response = data else: if '; ' in content_type: ( mime_string, additional_info ) = content_type.split( '; ', 1 ) else: ( mime_string, additional_info ) = ( content_type, '' ) if 'charset=' in additional_info: # this does utf-8, ISO-8859-4, whatever ( gumpf, charset ) = additional_info.split( '=' ) try: parsed_response = data.decode( charset ) except: parsed_response = data elif content_type == 'application/x-yaml': try: parsed_response = yaml.safe_load( data ) except yaml.error.YAMLError as e: raise HydrusExceptions.NetworkVersionException( 'Failed to parse a response object!' + os.linesep + HydrusData.ToUnicode( e ) ) elif content_type == 'application/json': if hydrus_service: parsed_response = HydrusSerialisable.CreateFromNetworkString( data ) else: parsed_response = data elif content_type == 'text/html': try: parsed_response = data.decode( 'utf-8' ) except: parsed_response = data else: parsed_response = data return ( parsed_response, size_of_response )
def Request(self, method, path_and_query, request_headers, body, report_hooks=[], response_to_path=False): if method == HC.GET: method_string = 'GET' elif method == HC.POST: method_string = 'POST' if 'User-Agent' not in request_headers: request_headers['User-Agent'] = 'hydrus/' + HC.u( HC.NETWORK_VERSION) # it is important to only send str, not unicode, to httplib # it uses += to extend the message body, which propagates the unicode (and thus fails) when # you try to push non-ascii bytes as the body (e.g. during a file upload!) method_string = str(method_string) path_and_query = str(path_and_query) request_headers = { str(k): str(v) for (k, v) in request_headers.items() } try: self._connection.request(method_string, path_and_query, headers=request_headers, body=body) response = self._connection.getresponse() except (httplib.CannotSendRequest, httplib.BadStatusLine): # for some reason, we can't send a request on the current connection, so let's make a new one and try again! self._RefreshConnection() self._connection.request(method_string, path_and_query, headers=request_headers, body=body) response = self._connection.getresponse() if response.status == 200 and response_to_path: (temp_path, size_of_response) = self._WriteResponseToPath( response, report_hooks) parsed_response = temp_path else: (parsed_response, size_of_response) = self._ParseResponse(response, report_hooks) response_headers = { k: v for (k, v) in response.getheaders() if k != 'set-cookie' } cookies = self._ParseCookies(response.getheader('set-cookie')) self._last_request_time = HC.GetNow() if response.status == 200: return (parsed_response, None, size_of_response, response_headers, cookies) elif response.status in (301, 302, 303, 307): location = response.getheader('Location') if location is None: raise Exception(parsed_response) else: url = location if ' ' in url: # some booru is giving daft redirect responses print(url) url = urllib.quote(url, safe='/?=&') print(url) if not url.startswith(self._scheme): # assume it is like 'index.php' or '/index.php', rather than 'http://blah.com/index.php' if url.startswith('/'): slash_sep = '' else: slash_sep = '/' url = self._scheme + '://' + self._host + slash_sep + url if response.status in (301, 307): # 301: moved permanently, repeat request # 307: moved temporarily, repeat request redirect_info = (method, url) elif response.status in (302, 303): # 302: moved temporarily, repeat request (except everyone treats it like 303 for no good f*****g reason) # 303: thanks, now go here with GET redirect_info = (HC.GET, url) return (parsed_response, redirect_info, size_of_response, response_headers, cookies) elif response.status == 304: raise HydrusExceptions.NotModifiedException() else: if response.status == 401: raise HydrusExceptions.PermissionException(parsed_response) elif response.status == 403: raise HydrusExceptions.ForbiddenException(parsed_response) elif response.status == 404: raise HydrusExceptions.NotFoundException(parsed_response) elif response.status == 426: raise HydrusExceptions.NetworkVersionException(parsed_response) elif response.status in (500, 501, 502, 503): raise Exception(parsed_response) else: raise Exception(parsed_response)
def _ParseResponse(self, response, report_hooks): content_length = response.getheader('Content-Length') if content_length is not None: content_length = int(content_length) data = '' for block in HC.ReadFileLikeAsBlocks(response, self.read_block_size): if HC.shutdown: raise Exception('Application is shutting down!') data += block if content_length is not None and len(data) > content_length: raise Exception('Response was longer than suggested!') for hook in report_hooks: hook(content_length, len(data)) size_of_response = len(data) content_type = response.getheader('Content-Type') if content_type is None: parsed_response = data else: if '; ' in content_type: (mime_string, additional_info) = content_type.split('; ', 1) else: (mime_string, additional_info) = (content_type, '') if 'charset=' in additional_info: # this does utf-8, ISO-8859-4, whatever (gumpf, charset) = additional_info.split('=') try: parsed_response = data.decode(charset) except: parsed_response = data elif content_type in HC.mime_enum_lookup and HC.mime_enum_lookup[ content_type] == HC.APPLICATION_YAML: try: parsed_response = yaml.safe_load(data) except Exception as e: raise HydrusExceptions.NetworkVersionException( 'Failed to parse a response object!' + os.linesep + u(e)) elif content_type == 'text/html': try: parsed_response = data.decode('utf-8') except: parsed_response = data else: parsed_response = data return (parsed_response, size_of_response)