I am writing a Python script that interacts with the Spotify API. To authenticate, I generate a url that looks something like this: https://accounts.spotify.com/authorize?response_type=token&client_id=<client_id_here>&redirect_uri=http%3A%2F%2F127.0.0.1%3A8083. Spotify then redirects me to my redirect uri, which is currently localhost (127.0.0.1:8083). Spotify attaches the access token as a fragment to the redirect uri. I need to access the uri fragment from Python.
Currently I am using the following code (the function generate_login_url() generates the accounts.spotify.com url I need)
webbrowser.open(generate_login_url())
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(('127.0.0.1', 8083))
sock.listen()
conn, _ = sock.accept()
with conn:
data = conn.recv(1024)
conn.sendall(data)
When I run this, I can see in the web browser that I have been redirected to the correct url (http://127.0.0.1:8083/#access_token=<access_token_here>&token_type=Bearer&expires_in=3600) but I cannot find a way to access the fragment from python. Calling conn.recv(1024) again causes a timeout, and the information I need is not found anywhere in data, which seems to just hold the user-agent string and the headers.
Related
I read that HTTP Pipelining is not activated by default in modern browsers
How can I implement a Persistent HTTP Connection with Pipelining in Python (like code socket from scratch) without using requests library to download all pdf file in folder slides from http://web.stanford.edu/class/cs224w/slides/
I tried to send request from scratch many times just using import Socket and Threading (because I don't able to use requests lib or anything else like requests to automatically send request) but don't gain any result.
I made a TCP socket connection like this
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
After that I make many sending-thread with the request with the format like this:
request = f"GET {path}{file_name} HTTP/1.1\r\nHost:{host}\r\nConnection: Keep-Alive\r\n\r\n"
Then I make many receiving-thread to receive data but Host return the response by turn.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I want to connect my laptop (and later a raspberry pi/Jetson nano) to a Server. The goal is to be able to send data to the server then process and evaluate it and send the output (GPS coordinates) back to the client (laptop/raspberry pi/Jetson nano).
Ideally, I would just plug in the public IP address of the Google Server into the code that is run on the client and connect to the server.
However, running the server code:
import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
and the client code:
import socket
HOST = '127.0.0.1' # The server's hostname or IP address
PORT = 65432 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
provided by: https://realpython.com/python-sockets/ .
Will only work with the default local IP address otherwise it returns a IP address couldn't be found error.
EDIT: The answer was more directed towards internet connection via the google cloud API. The solution illustrates this perfectly, however my question was not explicit enough sorry!
There's a large number of ways to do this, but I would recommend using either a GCE instance as your server, or an App Engine deployment. Cloud Run and Cloud Functions also would work. (EDIT: forgot k8s)
Note that when using a GCE instance you will need to open up your firewall as per documentation.
Also note that unless you assign a static IP address to the GCE instance, it will be ephemeral. If you use App Engine, you can just use https://project-id.appspot.com/ as the server address in your client.
You'll need to set up a simple web server using Flask, FastAPI or another webapp framework. It makes life easier to use a simple framework as it will take load of your hands.
You can have your client perform a request with the data it needs to send as parameters and have the web app perform magic and provide a response. I would highly advise to return a JSON response as this is more or less standard for APIs. (which your web app would basically be). Also, as you might know, JSON is easily converted into something useable in python.
See this very simple example below.
server code
from flask import Flask, request
import json
app = Flask(__name__)
longitude_divisor = 0.004167
#app.route("/api/gettimediff")
def gettimediff():
longitude = float(request.args.get("Longitude"))
# http://www.cs4fn.org/mobile/owntimezone.php
seconds = longitude / longitude_divisor
response = json.dumps({"seconds": seconds}, indent=4)
return response
#app.route("/api/switch")
def switch():
longitude = float(request.args.get("Longitude"))
latitude = float(request.args.get("Latitude"))
response = json.dumps({"Latitude": longitude, "Longitude": latitude})
return response
if __name__ == "__main__":
# This is used when running locally only. When deploying to Google App
# Engine, a webserver process such as Gunicorn will serve the app. This
# can be configured by adding an `entrypoint` to app.yaml.
# Flask's development server will automatically serve static files in
# the "static" directory. See:
# http://flask.pocoo.org/docs/1.0/quickstart/#static-files. Once deployed,
# App Engine itself will serve those files as configured in app.yaml.
app.run(host="127.0.0.1", port=8080, debug=True)
client code
import requests
import json
serveraddress = "http://127.0.0.1:8080/"
data = {"Latitude": 48.85837, "Longitude": 2.294481}
print("switch")
response = requests.get(
f"{serveraddress}api/switch",
params=data
)
print(data)
print(response.text)
print("seconds")
response = requests.get(
f"{serveraddress}api/gettimediff",
params=data
)
print(data)
print(response.text)
converted = json.loads(response.text)
print(converted)
I have some code that hosts a local server and when a user connects it will send them some html code, which works fine.
But I want it so if they connect to http://localhost:90/abc it will show something different. How can I get the exact url they connected to?
Here is my code:
import socket
sock = socket.socket()
sock.bind(('', 90))
sock.listen(5)
print("Listening...")
while True:
client, address = sock.accept()
print("Connection recieved: ", address)
print(The exact url they connected to.)
print()
client.send(b'HTTP/1.0 200 OK\r\n')
client.send(b"Content-Type: text/html\r\n\r\n")
client.send(b'<html><body><h1>Hello, User!</body></html>')
client.close()
sock.close()
I tried print(client.getpeername()[1]), but that gets the client ip, and if there is a similar way to get the ip they connected to it probably wont get the 'abc' part of the url.
Thanks in advance.
Socket's don't have a notion of URL, that's specific to the HTTP protocol which runs on top of a socket. For this reason, only part of the HTTP URL is even used in the creation of a socket.
|--1---|----2----|-3-|--4-|
http:// localhost :90 /abc
Specifies which protocol inside of TCP the URL uses
Specifies the remote host, either by IP address or hostname
Specifies the remote port and is optional
Specifies the path of the URL
Only parts 2 and 3 are actually known to a TCP socket though! This is because TCP is a very basic form of communication, HTTP adds a bunch of functionality on top of it like requests and responses and paths and so on.
Basically if you're implementing an HTTP server, knowing the /abc part is your job. Take a look at this example. The client actually sends the /abc part to the server, otherwise it has no way of knowing which path the request is for.
When the client connects to your server, it will send:
GET /abc HTTP/1.1
Host: localhost
more headers...
<blank line>
Your server needs to parse the GET line and extract /abc from that.
I have a code to start a simple socket sever on localhost. However, I want it to display a html page when it is accessed through browser. The html will contain two text fields and submit button. When user enters text in text fields and clicks on submit button, I want the program to read from text fields. How Can I Do That?
The instant answer (I hope so) to your question is in the last section The Answer - and, if I have interpreted your question wrong, let me know in the comment section.
The confusion - You are confusing the fundamentals - to display a html page, you simply need a server (localhost in your case), and the browser will use the HTTP/HTTPS protocol to fetch that content/response/html page. In Python (almost same for other languages) there are two levels of access to network services:
Low-level via sockets.
Higher-level via application level network protocols, like HTTP, FTP, etc.
Sockets - in plain english it is a functionality (interface) provided by the machine's operating system to implement client and server (for the higher-level network protocols) like communication between the processes. These processes can be running on a same machine or both processes on physically apart machines (e.g. requesting a website using browser).
A typical socket client is (asking for the desired html from browser):
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(("localhost", 80))
But to make it work you must already have server running (which will serve the html):
server_sock = socket.socket() # Create a socket object
server_sock.bind((localhost, 80)) # Bind to the port
server_sock.listen(5)
while True:
# lines for whatever we want server to do
The line server_sock.bind((localhost, 80)) has binded (assigned/allocated) the localhost:80 (a socket is basically 'host_name:port_number') to this server_sock i.e. any call/request to localhost:80 will be handled as per the lines in the above while True: block of the code above, can be a text response, HTML, etc.
Typical web scenario - We enter a website name www.google.com (which is resolved into an IP via DNS protocol - a whole another story) and hit enter, we'll get the Google's search homepage in response - Here you're the client, that is entering the website name and hitting enter is technically client_sock.connect('www.google.com', 80), and it only worked because on another (remote) machine/system/host they have server_socket binded and listening i.e.
server_sock.bind('machine's_IP', 80)
server_sock.listen(5)
while True:
#accept connections from outside
(client_socket, address) = server_socket.accept()
# here will be the lines which send us back the Google's
# homepage html as a response to our web request.
To sum-up, servers (webserver in your case) can be implemented using (almost) any programming languages e.g. python or C, etc, but the basis, the lowest layer, exactly where the data is passed between 2 processes whether on the same machine using locahost (loopback) or each process running on physically apart machine/host (typical web scenario ) via the HTTP (TCP) protocol rest upon sockets. Sockets are the fundamental building block from which HTTP, HTTPS, FTP, SMTP protocols (all of these are TCP-type protocols) are defined.
DNS, DHCP, VOIP protocols are UDP protocols but they too are built on top of sockets.
The Answer - To start, create a web_server.py and paste the following code (only to see how it works) and run the file as script i.e. from the file's location run "python
web_server.py" in command prompt/terminal:
#!/usr/bin/env python
import socket
host = 'localhost'
port = 80
server_sock = socket.socket(socket.AF_INET,\
socket.SOCK_STREAM) # Create a socket object
server_sock.bind((host , port)) # Bind to the port
print 'Starting server on', host, port
print 'The Web server URL for this would be http://%s:%d/' % (host, port)
server_sock.listen(5) # Now wait for client connection.
print 'Entering infinite loop; hit CTRL-C to exit'
while True:
# Establish connection with client.
client_sock, (client_host, client_port) = socket.socket.accept()
print 'Got connection from', client_host, client_port
client_sock.recv(1000) # should receive request from client. (GET ....)
client_sock.send('HTTP/1.0 200 OK\n')
client_sock.send('Content-Type: text/html\n')
client_sock.send('\n') # header and body should be separated by additional newline
# you can paste your 2 text field html here in the <body>
client_sock.send("""
<html>
<body>
<h1>Hello World</h1> this is my server!
</body>
</html>
""")
client_sock.close()
P.S. You have to implement a HTTP server (webserver) - which will definitely use the socket interface at the lowest level i.e.
server_sock.bind
server_sock.listen
server_sock.accept
I have these two Python scripts I'm using to attempt to work out how to send and receive POST requests in Python:
The Client:
import httplib
conn = httplib.HTTPConnection("localhost:8000")
conn.request("POST", "/testurl")
conn.send("clientdata")
response = conn.getresponse()
conn.close()
print(response.read())
The Server:
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
ADDR = "localhost"
PORT = 8000
class RequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
print(self.path)
print(self.rfile.read())
self.send_response(200, "OK")
self.end_headers()
self.wfile.write("serverdata")
httpd = HTTPServer((ADDR, PORT), RequestHandler)
httpd.serve_forever()
The problem is that the server hangs on self.rfile.read() until conn.close() has been called on the client but if conn.close() is called on the client the client cannot receive a response from the server. This creates a situation where one can either get a response from the server or read the POST data but never both. I assume there is something I'm missing here that will fix this problem.
Additional information:
conn.getresponse() causes the client to hang until the response is received from the server. The response doesn't appear to be received until the function on the server has finished execution.
There are a couple of issues with your original example. The first is that if you use the request method, you should include the message body you want to send in that call, rather than calling send separately. The documentation notes send() can be used as an alternative to request:
As an alternative to using the request() method described above, you
can also send your request step by step, by using the four functions
below.
You just want conn.request("POST", "/testurl", "clientdata").
The second issue is the way you're trying to read what's sent to the server. self.rfile.read() attempts to read the entire input stream coming from the client, which means it will block until the stream is closed. The stream won't be closed until connection is closed. What you want to do is read exactly how many bytes were sent from the client, and that's it. How do you know how many bytes that is? The headers, of course:
length = int(self.headers['Content-length'])
print(self.rfile.read(length))
I do highly recommend the python-requests library if you're going to do more than very basic tests. I also recommend using a better HTTP framework/server than BaseHTTPServer for more than very basic tests (flask, bottle, tornado, etc.).
Long time answered but came up during a search so I bring another piece of answer. To prevent the server to keep the stream open (resulting in the response never being sent), you should use self.rfile.read1() instead of self.rfile.read()