Skip to content

Commit

Permalink
Merge pull request #182 from RDFLib/edmond/fix-sparql-endpoint
Browse files Browse the repository at this point in the history
Fix: Prez SPARQL endpoint's handling of url encoding/decoding of queries in GET requests
  • Loading branch information
lalewis1 authored Nov 29, 2023
2 parents 4585cbb + 8861bad commit b56c66c
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 11 deletions.
8 changes: 6 additions & 2 deletions prez/routers/sparql.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

router = APIRouter(tags=["SPARQL"])

# TODO: Split this into two routes on the same /sparql path.
# One to handle SPARQL GET requests, the other for SPARQL POST requests.

@router.api_route("/sparql", methods=["GET"])

@router.get("/sparql")
async def sparql_endpoint(
query: str,
request: Request,
repo: Repo = Depends(get_repo),
):
Expand Down Expand Up @@ -48,7 +52,7 @@ async def sparql_endpoint(
headers=prof_and_mt_info.profile_headers,
)
else:
response = await repo.sparql(request)
response = await repo.sparql(query, request.headers.raw)
return StreamingResponse(
response.aiter_raw(),
status_code=response.status_code,
Expand Down
21 changes: 12 additions & 9 deletions prez/sparql/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from abc import ABC, abstractmethod
from typing import List
from typing import Tuple
from urllib.parse import quote_plus

import httpx
import pyoxigraph
from fastapi.concurrency import run_in_threadpool
from rdflib import Namespace, Graph, URIRef, Literal, BNode
from starlette.requests import Request

from prez.config import settings

Expand Down Expand Up @@ -87,20 +87,23 @@ async def tabular_query_to_table(self, query: str, context: URIRef = None):
await response.aread()
return context, response.json()["results"]["bindings"]

async def sparql(self, request: Request):
async def sparql(
self, query: str, raw_headers: list[tuple[bytes, bytes]], method: str = "GET"
):
"""Sends a starlette Request object (containing a SPARQL query in the URL parameters) to a proxied SPARQL
endpoint."""
url = httpx.URL(
url=settings.sparql_endpoint, query=request.url.query.encode("utf-8")
)
# TODO: This only supports SPARQL GET requests because the query is sent as a query parameter.

query_escaped_as_bytes = f"query={quote_plus(query)}".encode("utf-8")

# TODO: Global app settings should be passed in as a function argument.
url = httpx.URL(url=settings.sparql_endpoint, query=query_escaped_as_bytes)
headers = []
for header in request.headers.raw:
for header in raw_headers:
if header[0] != b"host":
headers.append(header)
headers.append((b"host", str(url.host).encode("utf-8")))
rp_req = self.async_client.build_request(
request.method, url, headers=headers, content=request.stream()
)
rp_req = self.async_client.build_request(method, url, headers=headers)
return await self.async_client.send(rp_req, stream=True)


Expand Down

0 comments on commit b56c66c

Please sign in to comment.