How to get form value using python sockets? - python

I created a simple website with forms, i want to get the input enterd on id 'message'
my code:
website.py
import socket
SERVER_HOST = '127.0.0.1'
SERVER_PORT = 8000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((SERVER_HOST, SERVER_PORT))
server_socket.listen(1)
print('Listening on port %s ...' % SERVER_PORT)
#sender
while True:
client_connection, client_address = server_socket.accept()
request = client_connection.recv(1024).decode()
print(request)
with open('form.html', 'r')as f:
file=f.read()
response = 'HTTP/1.0 200 OK\n\n'+file
client_connection.sendall(response.encode())
client_connection.close()
server_socket.close()
form.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>form</title>
</head>
<body>
<form action="/" method="get" accept-charset="utf-8">
<input type="text" name="message" id="message" value="" />
<input type="submit" name="submit" id="submit" value="submit" />
</form>
<script>
//what will be here?
</script>
</body>
</html>
can you help me to print the input enterd on id 'message' ?
using only socket or other internal libraries.

There is multiple way to do it :
Use XMLHttpRequest which make you able to do web request. This can be used to get a page. Example:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText); // good result !
}
};
xmlhttp.open("GET", "http://my.url/example", true);
xmlhttp.send();
Then, in you HTML page you just should return the result.
Use WebSocket
Server side
You have to use something that can support WebSocket. It's different from "basic" socket, because it will pass with HTTP protocol (but on 8000 port).
To do it, you should use Python Websocket. You can install it with pip install websocket-server.
This is my code:
import logging
from websocket_server import WebsocketServer
def new_client(client, server):
print("New client !")
def received_msg(client, server, message):
print("New message:", message)
server = WebsocketServer(host='127.0.0.1', port=8000, loglevel=logging.INFO)
server.set_fn_new_client(new_client)
server.set_fn_message_received(received_msg)
server.run_forever()
Client side
Here is the HTML part with the websocket utilisation :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>form</title>
</head>
<body>
<form action="/" method="get" accept-charset="utf-8">
<input type="text" name="message" id="message" value="" />
</form>
<button onclick="run()">Run</button>
</body>
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:8000");
socket.onopen = function (event) {
console.log("opened");
socket.send("Opened !");
};
function run() {
socket.send(JSON.stringify({ "message": document.getElementById("message").value }));
}
</script>
</html>
Finally
When you show HTML page, enter a message and click on "Run" :
INFO:websocket_server.websocket_server:Listening on port 8000 for clients..
INFO:websocket_server.websocket_server:Starting WebsocketServer on main thread.
New client !
New message: Opened !
New message: {"message":"value"}

Related

App build with eel framework not working on UI

I built the interface of a python script that sends sms using an api, it works normally but quad I try to send a message from the interface nothing happens, here is my code
This is main.py file
import eel
import os
from twilio.rest import Client
dirname = os.path.dirname('/Users/Admin/Desktop/App/')
eel.init(os.path.join(dirname,'web/'))
#eel.expose
def send_message(number, receiver, message):
# send sms
account_sid = ''
auth_token = ''
client = Client(account_sid, auth_token)
message = client.messages.create(from_=number, body=message, to=receiver)
print(message.sid)
eel.start('index.html')
script.js
document.getElementById("btn").addEventListener("click", function() {
var name = document.getElementById("number").value;
var email = document.getElementById("receiver").value;
var message = document.getElementById("message").value;
send_message(number, receiver, message);
});
function send_message(number, receiver, message) {
eel.send_message(number, receiver, message)(function(result) {
console.log(result);
});
}
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>App</title>
</head>
<body>
<div class="form">
<form onsubmit="eel.send_message(this.number.value, this.receiver.value, this.message.value); return false;">
<input type="number" name="name" id="number" placeholder="your number" required>
<input type="number" name="number" id="receiver" placeholder="Receiver" required>
<textarea name="message" id="message" cols="30" rows="10" placeholder="Enter message" required></textarea>
<input type="submit" value="Send" id="btn">
</form>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
I am trying to build an application that allows me to send sms from an interface using the eel framework

Pass HTML user input to Python variable

I'm trying to create a webserver with micropython in access point (hotspot) mode. My problem is that I don't know how to pass simple HTML user input to a python variable (username and password).
Flask/MicroWebSrv is not an option for me due to memory issues (using an ESP8266 with limited flash and RAM) and I don't really want to rebuild my webserver from scratch. Previous solutions based on CGI package is depreciated. Any other generic method?
import network
import socket
ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid=ap_ssid, password=ap_psw)
s = socket.socket()
s.bind(('', 80))
s.listen(5)
def webpage():
html = """
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1", charset="UTF-8">
<title>Login Form</title>
</head>
<body>
<div class="center">
<div class="header">
Login Form
</div>
<form method="post">
<input type="text" placeholder="Username" id="wifi_ssid" name="wifi_ssid">
<i class="far fa-envelope"></i>
<input id="wifi_psw" name="wifi_psw" type="password" placeholder="Password">
<i class="fas fa-lock" onclick="show()"></i>
<input type="submit" value="Sign in">
</form>
</div>
</body>
</html>"""
return html
while True:
conn, addr = s.accept()
request = conn.recv(1024)
response = webpage()
conn.send(response)
conn.close()

Receive data from HTML forms in fastapi [duplicate]

I am facing the following issue while trying to pass a value from an HTML form <input> element to the form's action attribute and send it to the FastAPI server.
This is how the Jinja2 (HTML) template is loaded:
# Test TEMPLATES
#app.get("/test",response_class=HTMLResponse)
async def read_item(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
My HTML form:
<form action="/disableSubCategory/{{subCatName}}">
<label for="subCatName">SubCategory:</label><br>
<input type="text" id="subCatName" name="subCatName" value=""><br>
<input type="submit" value="Disable">
</form>
My FastAPI endpoint to be called in the form action:
# Disable SubCategory
#app.get("/disableSubCategory/{subCatName}")
async def deactivateSubCategory(subCatName: str):
disableSubCategory(subCatName)
return {"message": "SubCategory [" + subCatName + "] Disabled"}
The error I get:
"GET /disableSubCategory/?subCatName=Barber HTTP/1.1" 404 Not Found
What I am trying to achieve is the following FastAPI call:
/disableSubCategory/{subCatName} ==> "/disableSubCategory/Barber"
Anyone who could help me understand what I am doing wrong?
Thanks.
Leo
Option 1
You can have the category name defined as Form parameter in the backend, and submit a POST request from the frontend using an HTML <form>, as described in Method 1 of this answer.
app.py
from fastapi import FastAPI, Form, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory='templates')
#app.post('/disable')
def disable_cat(cat_name: str = Form(...)):
return f'{cat_name} category has been disabled.'
#app.get('/', response_class=HTMLResponse)
def main(request: Request):
return templates.TemplateResponse('index.html', {'request': request})
templates/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Disable a category</h1>
<form method="post" action="/disable">
<label for="cat_name">Enter a category name to disable:</label><br>
<input type="text" id="cat_name" name="cat_name">
<input class="submit" type="submit" value="Submit">
</form>
</body>
</html>
Option 2
You can have the category name declared as query parameter in your endpoint, and in the frontend use a similar approach to the one demonstrated in your question to convert the value form the form <input> element into a query parameter, and then add it to the query string of the URL (in the action attribute).
Note that the below uses a GET request in contrast to the above (in this case, you need to use #app.get() in the backend and <form method="get" ... in the frontend, which is the default method anyway). Beware that most browsers cache GET requests (i.e., saved in browser's history), thus making them less secure compared to POST, as the data sent are part of the URL and visible to anyone who has access to the device. Thus, GET method should not be used when sending passwords or other sensitive information.
app.py
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory='templates')
#app.get('/disable')
def disable_cat(cat_name: str):
return f'{cat_name} category has been disabled.'
#app.get('/', response_class=HTMLResponse)
def main(request: Request):
return templates.TemplateResponse('index.html', {'request': request})
templates/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Disable a category</h1>
<form method="get" id="myForm" action='/disable{{ cat_name }}'>
<label for="cat_name">Enter a category name to disable:</label><br>
<input type="text" id="cat_name" name="cat_name">
<input class="submit" type="submit" value="Submit">
</form>
</body>
</html>
If you instead would like to use a POST request—which is a little safer than GET, as the parameters are not stored in the browser's history, and which makes more sense when updating content/state on the server, compared to GET that should be used when requesting (not modifying) data—you can define the FastAPI endpoint with #app.post() and replace the above template with the below (similar to Method 2 of this answer), which submits the form using POST method after transforming the form data into query parameters:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.getElementById("myForm").addEventListener("submit", function (e) {
var myForm = document.getElementById('myForm');
var qs = new URLSearchParams(new FormData(myForm)).toString();
myForm.action = '/disable?' + qs;
});
});
</script>
</head>
<body>
<h1>Disable a category</h1>
<form method="post" id="myForm">
<label for="cat_name">Enter a category name to disable:</label><br>
<input type="text" id="cat_name" name="cat_name">
<input class="submit" type="submit" value="Submit">
</form>
</body>
</html>
Option 3
You can still have it defined as path parameter, and use JavaScript in the frontend to modify the action attribute of the <form>, by passing the value of the form <input> element as path parameter to the URL, similar to what has been described earlier.
app.py
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory='templates')
#app.post('/disable/{name}')
def disable_cat(name: str):
return f'{name} category has been disabled.'
#app.get('/', response_class=HTMLResponse)
def main(request: Request):
return templates.TemplateResponse('index.html', {'request': request})
templates/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.getElementById("myForm").addEventListener("submit", function (e) {
var myForm = document.getElementById('myForm');
var catName = document.getElementById('catName').value;
myForm.action = '/disable/' + catName;
});
});
</script>
</head>
<body>
<h1>Disable a category</h1>
<form method="post" id="myForm">
<label for="catName">Enter a category name to disable:</label><br>
<input type="text" id="catName" name="catName">
<input class="submit" type="submit" value="Submit">
</form>
</body>
</html>
Option 4
If you would like to prevent the page from reloading/redirecting when hitting the submit button of the HTML <form> and rather get the results in the same page, you can use Fetch API, a JavaScript interface/library, to make an asynchronous HTTP request, similar to this answer, as well as this answer and this answer. Additionally, one can call the Event.preventDefault() function, as described in this answer, to prevent the default action. The example below is based on the previous option (i.e., Option 3); however, the same approach below (i.e., making an asynchronous HTTP request) can also be used for Options 1 & 2 demonstrated earlier, if you would like to keep the browser from refreshing the page on <form> submission.
app.py
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory='templates')
#app.post('/disable/{name}')
def disable_cat(name: str):
return f'{name} category has been disabled.'
#app.get('/', response_class=HTMLResponse)
def main(request: Request):
return templates.TemplateResponse('index.html', {'request': request})
templates/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.getElementById("myForm").addEventListener("submit", function (e) {
e.preventDefault() // Cancel the default action
var catName = document.getElementById('catName').value;
fetch('/disable/' + catName, {
method: 'POST',
})
.then(resp => resp.text()) // or, resp.json(), etc.
.then(data => {
document.getElementById("response").innerHTML = data;
})
.catch(error => {
console.error(error);
});
});
});
</script>
</head>
<body>
<h1>Disable a category</h1>
<form id="myForm">
<label for="catName">Enter a category name to disable:</label><br>
<input type="text" id="catName" name="catName">
<input class="submit" type="submit" value="Submit">
</form>
<div id="response"></div>
</body>
</html>
Just to provide you a feedback and keep track about the solution I've put in place.
As mentioned by #Chris, I went to the proposed solution 3.
Please find below my new code:
== FastAPI ==
# Test TEMPLATES
#app.get("/test",response_class=HTMLResponse)
async def read_item(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
# Disable SubCategory
#app.post("/disableSubCategory/{subCatName}")
async def deactivateSubCategory(subCatName: str):
disableSubCategory(subCatName)
return {"message": "Sub-Category [" + subCatName + "] Disabled"}
# Enable SubCategory
#app.post("/enableSubCategory/{subCatName}")
async def activateSubCategory(subCatName: str):
enableSubCategory(subCatName)
return {"message": "Sub-Category [" + subCatName + "] Enabled"}
== HTML ==
<html>
<head>
<title>Item Details</title>
<link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.getElementById("disableSubCategory").addEventListener("submit", function (e) {
var myForm = document.getElementById('disableSubCategory');
var disableSubCatName = document.getElementById('id_disableSubCategory').value;
myForm.action = '/disableSubCategory/' + disableSubCatName;
});
});
</script>
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.getElementById("enableSubCategory").addEventListener("submit", function (e) {
var myForm2 = document.getElementById('enableSubCategory');
var enableSubCatName = document.getElementById('id_enableSubCategory').value;
myForm2.action = '/enableSubCategory/' + enableSubCatName;
});
});
</script>
</head>
<body>
<form id="disableSubCategory" enctype="multipart/form-data" method="post">
<label for="subCatName">SubCategory:</label><br>
<input type="text" id="id_disableSubCategory" value=""><br>
<input type="submit" value="Disable" id="disable">
</form>
<form id="enableSubCategory" enctype="multipart/form-data" method="post">
<label for="subCatName">SubCategory:</label><br>
<input type="text" id="id_enableSubCategory" value=""><br>
<input type="submit" value="Enable" id="enable">
</form>
</body>
</html>

Why am i getting 403 error when i submit a processing request?

I start python local server on ubuntu, server.py:
from http.server import HTTPServer, CGIHTTPRequestHandler
server_address = ("", 8000)
httpd = HTTPServer(server_address, CGIHTTPRequestHandler)
httpd.serve_forever()
it's start and open index.html:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Обработка данных форм</title>
</head>
<body>
<form action="/cgi-bin/form.py">
<input type="text" name="TEXT_1">
<input type="text" name="TEXT_2">
<input type="submit">
</form>
</body>
</html>
Then i send GET request i have 403 Code Error:
Error response
Error code: 403
Message: CGI script is not executable ('/cgi-bin/form.py').
Error code explanation: HTTPStatus.FORBIDDEN - Request forbidden -- authorization will not help.
form.py:
#!/usr/bin/env python3
import cgi
form = cgi.FieldStorage()
text1 = form.getfirst("TEXT_1", "не задано")
text2 = form.getfirst("TEXT_2", "не задано")
print("Content-type: text/html\n")
print("""<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Обработка данных форм</title>
</head>
<body>""")
print("<h1>Обработка данных форм!</h1>")
print("<p>TEXT_1: {}</p>".format(text1))
print("<p>TEXT_2: {}</p>".format(text2))
print("""</body>
</html>""")
I try on Win 10 and it works well.
I know about start server on Linyx like this:
python3 -m http.server --cgi
but i need start from file.
Ok, it's easy then i think:
chmod +x form.py
Now it's work.

change route and send message using socketio but socketio is working

<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',()=>{
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
socket.on('connect',()=>{
console.log('connected');
document.querySelector('#submit').onclick =() =>{
const user= document.querySelector('#user').value;
const room = document.querySelector('#room').value;
socket.emit('join',{'user':user,'room':room});
console.log('emitted');
return false;
};
});
});
</script>
</head>
<body>
<form id="new-task" action="{{ url_for('chat') }}" method="post">
<input type="text" autocomplete="off" autofocus id="user" placeholder="username">
<input type="text" autocomplete="off" autofocus id="room" placeholder="room">
<input type="submit" id="submit" value="join">
</form>
</body>
</html>
localhost:5000 open index.html page , when i click on submit only socketio is working but url is not being changed .
import os
import requests
from flask import Flask,jsonify,render_template,request
from flask_socketio import SocketIO,emit,join_room,leave_room,send
from werkzeug import secure_filename
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
socketio=SocketIO(app)
#app.route("/")
def index():
return render_template("index.html")
#app.route("/chat" ,methods=["POST"])
def chat():
print("running chat")
return render_template("chat.html")
#socketio.on('join')
def on_join(data):
username = data['user']
room = data['room']
join_room(room)
emit('chat',{'username':username},room=room)
print("room has been allocated")
when i did only url_for without socketio i was able to change route but now it does not seem to work. in console and cmd i am able to see socketio working but chat route is not working

Categories