La SCRO avec python baseHTTPserver 501 (méthode non prise en charge ("OPTIONS")) dans chrome
Salut j'ai besoin d'aide avec l'authentification de base, tandis qu'un ajax get/post demande à un python baseHTTPserver.
J'ai été en mesure de modifier quelques lignes de code dans le script python pour l'envoi de la SCRO en-têtes. Il fonctionne très bien dans les navigateurs modernes quand j'ai désactiver http authentification de base.
Si l'authentification est activée, je reçois un 501 (méthode non prise en charge ("OPTIONS")) erreur (j'ai chrome).
Je peux passer des heures à trouver une solution un maintenant, je pense que iam sur une bonne voie. Comme je l'ai lu dans les rubriques ci-dessous la HTTPRequestHandler pourrait causer le problème, mais mon pyton compétences ne sont pas suffisantes pour résoudre le problème.
Si trouvé quelques post sur ce sujet ici et ici mais iam pas en mesure de l'obtenir en cours d'exécution avec le script que j'ai. Quelqu'un peut-il m'aider à le remettre en marche?
De l'aide ou des idées sont serait très appréciée.
# Copyright 2012-2013 Eric Ptak - trouch.com
#
# 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.
import os
import threading
import re
import codecs
import mimetypes as mime
import logging
from webiopi.utils import *
if PYTHON_MAJOR >= 3:
import http.server as BaseHTTPServer
else:
import BaseHTTPServer
try :
import _webiopi.GPIO as GPIO
except:
pass
WEBIOPI_DOCROOT = "/usr/share/webiopi/htdocs"
class HTTPServer(BaseHTTPServer.HTTPServer, threading.Thread):
def __init__(self, host, port, handler, context, docroot, index, auth=None):
BaseHTTPServer.HTTPServer.__init__(self, ("", port), HTTPHandler)
threading.Thread.__init__(self, name="HTTPThread")
self.host = host
self.port = port
if context:
self.context = context
if not self.context.startswith("/"):
self.context = "/" + self.context
if not self.context.endswith("/"):
self.context += "/"
else:
self.context = "/"
self.docroot = docroot
if index:
self.index = index
else:
self.index = "index.html"
self.handler = handler
self.auth = auth
self.running = True
self.start()
def get_request(self):
sock, addr = self.socket.accept()
sock.settimeout(10.0)
return (sock, addr)
def run(self):
info("HTTP Server binded on http://%s:%s%s" % (self.host, self.port, self.context))
try:
self.serve_forever()
except Exception as e:
if self.running == True:
exception(e)
info("HTTP Server stopped")
def stop(self):
self.running = False
self.server_close()
class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
logger = logging.getLogger("HTTP")
def log_message(self, fmt, *args):
self.logger.debug(fmt % args)
def log_error(self, fmt, *args):
pass
def version_string(self):
return VERSION_STRING
def checkAuthentication(self):
if self.server.auth == None or len(self.server.auth) == 0:
return True
authHeader = self.headers.get('Authorization')
if authHeader == None:
return False
if not authHeader.startswith("Basic "):
return False
auth = authHeader.replace("Basic ", "")
if PYTHON_MAJOR >= 3:
auth_hash = encrypt(auth.encode())
else:
auth_hash = encrypt(auth)
if auth_hash == self.server.auth:
return True
return False
def requestAuthentication(self):
self.send_response(401)
self.send_header("WWW-Authenticate", 'Basic realm="webiopi"')
self.end_headers();
def sendResponse(self, code, body=None, type="text/plain"):
if code >= 400:
if body != None:
self.send_error(code, body)
else:
self.send_error(code)
else:
self.send_response(code)
self.send_header("Cache-Control", "no-cache")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "POST, GET")
self.send_header("Access-Control-Allow-Headers", " X-Custom-Header")
if body != None:
self.send_header("Content-Type", type);
self.end_headers();
self.wfile.write(body.encode())
def findFile(self, filepath):
if os.path.exists(filepath):
if os.path.isdir(filepath):
filepath += "/" + self.server.index
if os.path.exists(filepath):
return filepath
else:
return filepath
return None
def serveFile(self, relativePath):
if self.server.docroot != None:
path = self.findFile(self.server.docroot + "/" + relativePath)
if path == None:
path = self.findFile("./" + relativePath)
else:
path = self.findFile("./" + relativePath)
if path == None:
path = self.findFile(WEBIOPI_DOCROOT + "/" + relativePath)
if path == None and (relativePath.startswith("webiopi.") or relativePath.startswith("jquery")):
path = self.findFile(WEBIOPI_DOCROOT + "/" + relativePath)
if path == None:
return self.sendResponse(404, "Not Found")
realPath = os.path.realpath(path)
if realPath.endswith(".py"):
return self.sendResponse(403, "Not Authorized")
if not (realPath.startswith(os.getcwd())
or (self.server.docroot and realPath.startswith(self.server.docroot))
or realPath.startswith(WEBIOPI_DOCROOT)):
return self.sendResponse(403, "Not Authorized")
(type, encoding) = mime.guess_type(path)
f = codecs.open(path, encoding=encoding)
data = f.read()
f.close()
self.send_response(200)
self.send_header("Content-Type", type);
self.send_header("Content-Length", os.path.getsize(realPath))
self.end_headers()
self.wfile.write(data)
def processRequest(self):
self.request.settimeout(None)
if not self.checkAuthentication():
return self.requestAuthentication()
request = self.path.replace(self.server.context, "/").split('?')
relativePath = request[0]
if relativePath[0] == "/":
relativePath = relativePath[1:]
if relativePath == "webiopi" or relativePath == "webiopi/":
self.send_response(301)
self.send_header("Location", "/")
self.end_headers()
return
params = {}
if len(request) > 1:
for s in request[1].split('&'):
if s.find('=') > 0:
(name, value) = s.split('=')
params[name] = value
else:
params[s] = None
compact = False
if 'compact' in params:
compact = str2bool(params['compact'])
try:
result = (None, None, None)
if self.command == "GET":
result = self.server.handler.do_GET(relativePath, compact)
elif self.command == "POST":
length = 0
length_header = 'content-length'
if length_header in self.headers:
length = int(self.headers[length_header])
result = self.server.handler.do_POST(relativePath, self.rfile.read(length), compact)
else:
result = (405, None, None)
(code, body, type) = result
if code > 0:
self.sendResponse(code, body, type)
else:
if self.command == "GET":
self.serveFile(relativePath)
else:
self.sendResponse(404)
except (GPIO.InvalidDirectionException, GPIO.InvalidChannelException, GPIO.SetupException) as e:
self.sendResponse(403, "%s" % e)
except ValueError as e:
self.sendResponse(403, "%s" % e)
except Exception as e:
self.sendResponse(500)
raise e
def do_GET(self):
self.processRequest()
def do_POST(self):
self.processRequest()
OriginalL'auteur user1532132 | 2013-05-16
Vous devez vous connecter pour publier un commentaire.
Le client doit émettre deux demandes, l'une des OPTIONS, puis la requête GET. La solution n'est pas optimale, car nous répondons à la demande d'OPTIONS avec un contenu.
Nous devons répondre à la demande OPTIONS correctement. Si nous le faisons, le client émet la requête GET après la réception d'une réponse adéquate.
J'ai fait le 501 méthode non prise en charge ("OPTIONS")) causée par la SCRO et en demandant le "Content-Type: application/json; charset=utf-8".
Pour résoudre l'erreur, j'ai activé la SCRO en do_OPTIONS et permis à ses clients de demander un type de contenu spécifique.
Ma solution:
OriginalL'auteur jgrocha
Ai eu de travail:
Ajax envoyer un
OPTIONS
demande au serveur, vous devez ajouter undo_options
méthode pourBaseHTTPRequestHandler
sans authentification (envoyer une réponse code 200).Après cela, vous pouvez appeler la fonction pour le traitement de la demande, comme d'habitude.
, Voici ma solution (vérifié dans Safari 6.x, Firefox 20, Chrome26 sur OS X):
La deuxième chose que vous devez changer, c'est que vous devez ajouter un en-tête de réponse dans le
processRequest
fonction. Ajouter Access-Control-Allow-en-Têtes:l'Autorisation, par exemple commeself.send_header("Access-Control-Allow-Headers", "Authorization")
pour permettre à l'ajax pour envoyer le jeton d'authentification de base.Le travail de script:
OriginalL'auteur user1532132
L'erreur est déclenchée parce que vous n'avez pas de
do_OPTIONS
méthode sur votreHTTPHandler
. Il va traiterOPTIONS
demandes. Je soupçonne que vous allez avoir d'autres problèmes, mais c'est un bon début 😉Lorsque vous dites qu'il "ne fonctionne pas", ça veut dire quoi ? Le message d'erreur de changement ?
Aussi, avez-vous une raison de ne pas utiliser un outil comme
Werkzeug
pour faciliter ce genre de travail ?désolé pour beeing de manière imprécise (d'habitude je n'aime pas ce genre de comportement, mais parfois je me surprends à le faire...) "ne fonctionne pas" signifie dans mon cas, le serveur d'arrêt de travail et ne donne aucune réponse. Iam généralement ne fonctionne pas avec python donc je n'ai pas tellement d'informations sur le débogage, encore. Comme je l'ai vu Werkzeug ne fonctionnent pas pour moi car je dois utiliser python 3.2 et werkzeug est supporter jusqu'à 2,7. Faire le do_OPTIONS méthode doit être appelée avant que la base de l'authentification ou après?
Eh bien, si elle cesse de fonctionner, vous devriez avoir un message d'erreur dans la console. Droit ? Votre code est assez long et compliqué et je vais avoir un moment difficile de débogage par un peu de le lire 😉
OriginalL'auteur Martin Maillard