Esempio n. 1
0
    def parse_request(self, conn: socket) -> Request:
        # Все чтение сокета делал через файлы, так удобнее читать построчно
        file = conn.makefile('rb')
        data = file.readline(1024*64)

        # Нагуглил, что хедеры обязаны быть в этой кодировке
        line = data.decode('iso-8859-1')
        line = line.strip().split()
        if len(line) != 3:  # Ожидаем метод, цель и протокол
            raise e.BadRequest('Request first line have to be 3 parts')
        method, target, proto = line

        # Перенаправляем / на /index.html
        if target == '/':
            target = '/index.html'

        # Других скорее всего и не будет, но на всякий
        if proto != 'HTTP/1.1':
            raise e.UnexpectedProto('Unexpected HTTP version')

        headers = self.parse_headers(file)
        host = headers.get('Host')
        if not host or host.strip() not in [self.__host, f'{self.__host}:{self.__port}']:
            raise e.BadRequest('Not found')
        return Request(method, target, proto, headers, file)
Esempio n. 2
0
 def _cleanSearchSort(self, sort):
     sort = '%s:asc' % sort if ':' not in sort else sort
     scol, sdir = sort.lower().split(':')
     lookup = {}
     for s in self.ALLOWED_SORT:
         lookup[s.lower()] = s
     if scol not in lookup:
         raise exceptions.BadRequest('Unknown sort column: %s' % scol)
     if sdir not in ('asc', 'desc'):
         raise exceptions.BadRequest('Unknown sort dir: %s' % sdir)
     return '%s:%s' % (lookup[scol], sdir)
Esempio n. 3
0
 def handle_response(self, response, content):
     """Validate HTTP response
     """
     status = response.status_code
     if status in (301, 302, 303, 307):
         raise exceptions.Redirection(response, content)
     elif 200 <= status <= 299:
         return json.loads(content) if content else {}
     elif status == 400:
         raise exceptions.BadRequest(response, content)
     elif status == 401:
         raise exceptions.UnauthorizedAccess(response, content)
     elif status == 403:
         raise exceptions.ForbiddenAccess(response, content)
     elif status == 404:
         raise exceptions.ResourceNotFound(response, content)
     elif status == 405:
         raise exceptions.MethodNotAllowed(response, content)
     elif status == 409:
         raise exceptions.ResourceConflict(response, content)
     elif status == 410:
         raise exceptions.ResourceGone(response, content)
     elif status == 422:
         raise exceptions.ResourceInvalid(response, content)
     elif 401 <= status <= 499:
         raise exceptions.ClientError(response, content)
     elif 500 <= status <= 599:
         raise exceptions.ServerError(response, content)
     else:
         raise exceptions.ConnectionError(
             response, content, "Unknown response code: #{response.code}")
Esempio n. 4
0
    def query(self, path, method=None, **kwargs):
        method = method or self.session.get
        url = self.buildUrl(path, includeToken=True)
        # If URL is empty, try refresh resources and return empty set for now
        if not url:
            util.WARN_LOG(
                "Empty server url, returning None and refreshing resources")
            plexapp.refreshResources(True)
            return None
        util.LOG('{0} {1}'.format(
            method.__name__.upper(),
            re.sub('X-Plex-Token=[^&]+', 'X-Plex-Token=****', url)))
        try:
            response = method(url, **kwargs)
            if response.status_code not in (200, 201):
                codename = http.status_codes.get(response.status_code,
                                                 ['Unknown'])[0]
                raise exceptions.BadRequest('({0}) {1}'.format(
                    response.status_code, codename))
            data = response.text.encode('utf8')
        except asyncadapter.TimeoutException:
            util.ERROR()
            plexapp.refreshResources(True)
            return None
        except http.requests.ConnectionError:
            util.ERROR()
            return None

        return ElementTree.fromstring(data) if data else None
Esempio n. 5
0
    def clean_models(self):
        """
        Invoked by ``validate``
        Calls ``full_clean()`` on all model instances in ``request.data``.

        Returns:
            None
        Raises:
            exceptions.BadRequest: When ``full_clean`` first throws a
            ValidationError. The exceptions.BadRequest exception is raised at
            the very first time that we encounter a ValidationError.
        """
        # TODO: Add the exclude parameter in the signature of the method.
        # Call full_clean with ``exclude``, so that we can exclude any models
        # fields we want from the validation.
        for element in isinstance(self.request.data, self.model) \
                and [self.request.data] or self.request.data:
            try:
                element.full_clean()
            except ValidationError, e:
                # When a ValidationError exception e is raised by
                # ``model.clean_fields``, it has the parameter:
                # e.message_dict = {'field1': 'error string',
                #                   'field2':  'error string, ...}
                # When it's raised by ``clean`` e has the parameter:
                # e.message_dict = {NON_FIELD_ERRORS: [<error string>]}
                raise exceptions.BadRequest(e.message_dict)
Esempio n. 6
0
 def _init(self):
     response = http.POST(self.INIT)
     if response.status_code != http.codes.created:
         codename = http.status_codes.get(response.status_code)[0]
         raise exceptions.BadRequest('({0}) {1}'.format(response.status_code, codename))
     data = ElementTree.fromstring(response.text.encode('utf-8'))
     self.pin = data.find('code').text
     self.id = data.find('id').text
Esempio n. 7
0
    def query(self, path, method=None, token=None, **kwargs):
        method = method or http.requests.get
        url = self.getURL(path)
        util.LOG('{0} {1}'.format(method.__name__.upper(), url))
        response = method(url, headers=self.headers(token), timeout=util.TIMEOUT, **kwargs)
        if response.status_code not in (200, 201):
            codename = http.status_codes.get(response.status_code)[0]
            raise exceptions.BadRequest('({0}) {1}'.format(response.status_code, codename))
        data = response.text.encode('utf8')

        return ElementTree.fromstring(data) if data else None
Esempio n. 8
0
    def query(self, path, method=None, **kwargs):
        method = method or self.session.get
        url = self.buildUrl(path, includeToken=True)
        util.LOG('{0} {1}'.format(
            method.__name__.upper(),
            re.sub('X-Plex-Token=[^&]+', 'X-Plex-Token=****', url)))
        response = method(url, **kwargs)
        if response.status_code not in (200, 201):
            codename = http.status_codes.get(response.status_code,
                                             ['Unknown'])[0]
            raise exceptions.BadRequest('({0}) {1}'.format(
                response.status_code, codename))
        data = response.text.encode('utf8')

        return ElementTree.fromstring(data) if data else None
Esempio n. 9
0
    def listChoices(self, category, libtype=None, **kwargs):
        """ List choices for the specified filter category. kwargs can be any of the same
            kwargs in self.search() to help narrow down the choices to only those that
            matter in your current context.
        """
        if category in kwargs:
            raise exceptions.BadRequest(
                'Cannot include kwarg equal to specified category: %s' %
                category)
        args = {}
        for subcategory, value in kwargs.items():
            args[category] = self._cleanSearchFilter(subcategory, value)
        if libtype is not None:
            args['type'] = plexobjects.searchType(libtype)
        query = '/library/sections/%s/%s%s' % (self.key, category,
                                               util.joinArgs(args))

        return plexobjects.listItems(self.server, query, bytag=True)
Esempio n. 10
0
    def _do_request(self):
        if self._token:
            self._headers['Authorization'] = 'Bearer {0}'.format(self._token)

        response = requests.request(self._method,
                                    url=self._url,
                                    headers=self._headers,
                                    data=self._payload)
        try:
            response = response.json()
        except json.decoder.JSONDecodeError:
            raise Exception(response.text)

        if 'error' in response:
            raise Exception('Error: {0}. {1}.'.format(response.get('error'),
                                                      response.get('message')))
        elif response == "{'message': ''}":
            raise exceptions.BadRequest()

        return response
Esempio n. 11
0
    def _cleanSearchFilter(self, category, value, libtype=None):
        # check a few things before we begin
        if category not in self.ALLOWED_FILTERS:
            raise exceptions.BadRequest('Unknown filter category: %s' %
                                        category)
        if category in self.BOOLEAN_FILTERS:
            return '1' if value else '0'
        if not isinstance(value, (list, tuple)):
            value = [value]
        # convert list of values to list of keys or ids
        result = set()
        choices = self.listChoices(category, libtype)
        lookup = {}
        for c in choices:
            lookup[c.title.lower()] = c.key

        allowed = set(c.key for c in choices)
        for item in value:
            item = str(
                item.id if isinstance(item, media.MediaTag) else item).lower()
            # find most logical choice(s) to use in url
            if item in allowed:
                result.add(item)
                continue
            if item in lookup:
                result.add(lookup[item])
                continue
            matches = [k for t, k in lookup.items() if item in t]
            if matches:
                map(result.add, matches)
                continue
            # nothing matched; use raw item value
            util.LOG(
                'Filter value not listed, using raw item value: {0}'.format(
                    item))
            result.add(item)
        return ','.join(result)
Esempio n. 12
0
    def _request(self,
                 op,
                 url,
                 data=None,
                 blocking=True,
                 retry_after_auth=False):
        retried = 0
        while True:
            try:
                if (op.upper() == 'GET'):
                    (status, content) = self._http_get(url,
                                                       headers=self._headers,
                                                       query_params=data)
                elif (op.upper() == 'POST'):
                    (status, content) = self._http_post(url,
                                                        body=data,
                                                        headers=self._headers)
                elif (op.upper() == 'DELETE'):
                    (status,
                     content) = self._http_delete(url,
                                                  body=data,
                                                  headers=self._headers)
                elif (op.upper() == 'PUT'):
                    (status, content) = self._http_put(url,
                                                       body=data,
                                                       headers=self._headers)
                else:
                    raise ValueError
            except ConnectionError as e:
                if not blocking:
                    raise

                retried += 1
                time.sleep(1)
                self._create_api_server_session()
                continue

            if status == 200:
                return content

            # Exception Response, see if it can be resolved
            if status == 401:
                if retry_after_auth:
                    raise exceptions.AuthenticationFailed(content)
                else:
                    self._headers = self._authenticate(content, self._headers)
                    # Recursive call after authentication (max 1 level)
                    content = self._request(op,
                                            url,
                                            data=data,
                                            retry_after_auth=True)
                return content
            elif status == 404:
                raise exceptions.NoIdError(
                    'Error: oper %s url %s body %s response %s' %
                    (op, url, data, content))
            elif status == 403:
                raise exceptions.PermissionDenied(content)
            elif status == 409:
                raise exceptions.RefsExistError(content)
            elif status == 504:
                # Request sent to API server, but no response came within lb timeout
                raise exceptions.TimeOutError('Gateway Timeout 504')
            elif status in [502, 503]:
                # 502: API server died after accepting request, so retry
                # 503: no API server available even before sending the request
                if not blocking:
                    raise exceptions.ServiceUnavailableError(
                        'Service Unavailable Timeout %d' % status)

                retried += 1
                time.sleep(1)
                continue
            elif status == 400:
                raise exceptions.BadRequest(status, content)
            else:  # Unknown Error
                raise exceptions.HttpError(status, content)