What is the order of HTTP responses, data, and error, and are they guaranteed to be in that order? - apache

I am debugging/testing the part of my app that sends an HTTP POST, with a file to upload, to a 3rd party server and need to be sure of the order of the info that server sends back.
Below is a very trimmed down sample of how I handle what is returned by the server.
At this moment, am debugging for files sent that exceed the LimitRequestBody size set in Apache. Yes, I do check file size in my app before sending, but am trying to debug for anything possible, i.e. malicious bot sending data outside of my app.
What I can't seem to find online is the lifecycle of what a server will send back in terms of the response, data, and error, and need to be sure I will get them back in this order:
Response
Data
and if there's an error:
Error (and then nothing else)
uploadSession.dataTask(with: upFile.toUrl!)
{ (data, response, error) in
if let response = response {
upLoadInvClass.upResp(resp: response)
}
if let error = error {
upLoadInvClass.upErr(error: error)
}
if let data = data {
upLoadInvClass.upData(data: data)
}
}.resume()

Related

Error: Network Connection Lost - saving form data (file) to R2 bucket

I have this handler in my worker:
const data = await event.request.formData();
const key = data.get('filename');
const file = data.get('file');
if (typeof key !== 'string' || !file) {
return res.send(
{ message: 'Post body is not valid.' },
undefined,
400
);
}
await BUCKET.put(key, file);
return new Response(file);
If I comment out the await BUCKET.put(key, file); line, then I get the response of the file as expected. But with that line in the function, I get the error:
Uncaught (in promise) Error: Network connection lost.
I have confirmed that by changing the put to a get, I can retrieve files from that bucket, so there doesn't seem to be a problem with the connection itself.
Are you still having this problem? I'll need your account ID to figure out what's going on. If you DM me (Vitali) on Discord your account ID (& this SO link for context) I can probably help you out (or email me directly at cloudflare.com using vlovich as the account if you don't have/don't want to sign up on Discord). I'm the tech lead for R2.
EDIT 2022-09-07.
I just noticed that you're calling formData on the request. This is causing you to read the object into RAM. Workers has a 128 MiB limit so what's likely happening is that you're exceeding that limit (probably egregiously since we do give some buffer) and thus Cloudflare is terminating your Worker.
What you'll want to do is make sure you upload the file raw (not as a form) and access the raw ReadableStream. Alternatively, you can try writing a TransformStream to parse out the payload in a streaming fashion if you're confident the file payload (& any metadata you need) will come after the name. Usually it's easier to change your upload mechanism.

Custom error status code with gqlgen + go gin

Recently I have been updating my GO REST APIs into graphQl API's and I came across issue where I am unable to customise my status code with gqlgen.
Response I got
Headers
Status Code: 200 OK
{
data: null,
errors: [
{message: "Unauthorized access", path: ["..."]}
]
}
Expected Header
Status Code: 401 UNAUTHORISED
Any help would be really appreciating!
Assume you have a gqlgen resolver similar to this:
func (r *queryResolver) SecretItems(ctx context.Context, userID string,
password string) ([]SecretItems, error) {
// ...
if !isAuthorized(userID, password) {
return nil, errors.New("Unauthorized access")
}
// ...
}
then the described behavior is expected. Errors should be returned as part of
the response body.
GraphQL is transport agnostic. While it is often served over HTTP, it might be
served over other client-server Protocols as well. Handling errors in the
response body requires no assumptions about the protocol. Hence, you shouldn't
rely on HTTP status codes.
Handling errors in the response body has another advantage: Assume a request
contains multiple queries. Some of them succeed, some of them fail. Then the
response can contain the result of successful queries under data and errors
related to failed queries under errors.
References:
GraphQL website
Specification: Response
Hasura: GraphQL vs REST
Possible reason why you expected a 401 status code
The gqlgen docs on
authentication contain an example
where 401 status code is returned.
Why? This happens in a http handler used as middleware on the chi http server.
The 401 status code is not returned by a GraphQL resolver.

sending the same request multiple times in a raw. some return with status code 204 and some are ok

I'm sending a post request to the same url multiple times in a row. Some of the requests return 200 status code and some return 204 saying no content. the request updates some content in a mongo database. I don't know if this is relevant. What could cause this problem?
My index.js:
app.post('/updatetrialsession',authenticateJWT ,(req,res)=>{
User.findOne({username:req.user.username}).then(user=>{
var trialIdx=user.examTrials.findIndex(it=>it.trialId===req.body.trialId)
var questionIdx=req.body.questionIdx
if(trialIdx!==-1){
user.examTrials[trialIdx].questions[questionIdx]=req.body.question
user.examTrials[trialIdx].currentQuestion=questionIdx+1
user.examTrials[trialIdx].countDown=req.body.countDown
user.examTrials[trialIdx].numOfSolved=req.body.numOfSolved
var filter={
'username':user.username
}
var update={
$set:{
'examTrials':user.examTrials
}
}
User.findOneAndUpdate(filter,update).then(user=>{
console.log('updated')
res.json({
status:"success"
})
})
}
})
})
Note: all requests go to this url "/epdatetrialsession".
when there's a 20 sec gap between each request everything works just fine. but when the server get flooded with say a request every 2 seconds or so, some return with 204 status code
I have had the same issue once. In my experience, When sending multiple number of requests to the server within a very short period of time, sometimes the server fails to answer all of them. Depends on the server capability. Did you try to check this by, sending the request for only the ones which returns 204 one at a time and see whether they still returns a 204? If so, the server has responded correctly even when sending the requests in a row. But if the server return a content with 200 when sending one at a time, then the issue might be with the server when handling multiple requests at a time.

Soundcloud API /stream endpoint giving 401 error

I'm trying to write a react native app which will stream some tracks from Soundcloud. As a test, I've been playing with the API using python, and I'm able to make requests to resolve the url, pull the playlists/tracks, and everything else I need.
With that said, when making a request to the stream_url of any given track, I get a 401 error.
The current url in question is:
https://api.soundcloud.com/tracks/699691660/stream?client_id=PGBAyVqBYXvDBjeaz3kSsHAMnr1fndq1
I've tried it without the ?client_id..., I have tried replacing the ? with &, I've tried getting another client_id, I've tried it with allow_redirects as both true and false, but nothing seems to work. Any help would be greatly appreciated.
The streamable property of every track is True, so it shouldn't be a permissions issue.
Edit:
After doing a bit of research, I've found a semi-successful workaround. The /stream endpoint of the API is still not working, but if you change your destination endpoint to http://feeds.soundcloud.com/users/soundcloud:users:/sounds.rss, it'll give you an RSS feed that's (mostly) the same as what you'd get by using the tracks or playlists API endpoint.
The link contained therein can be streamed.
Okay, I think I have found a generalized solution that will work for most people. I wish it were easier, but it's the simplest thing I've found yet.
Use API to pull tracks from user. You can use linked_partitioning and the next_href property to gather everything because there's a maximum limit of 200 tracks per call.
Using the data pulled down in the JSON, you can use the permalink_url key to get the same thing you would type into the browser.
Make a request to the permalink_url and access the HTML. You'll need to do some parsing, but the url you'll want will be something to the effect of:
"https://api-v2.soundcloud.com/media/soundcloud:tracks:488625309/c0d9b93d-4a34-4ccf-8e16-7a87cfaa9f79/stream/progressive"
You could probably use a regex to parse this out simply.
Make a request to this url adding ?client_id=... and it'll give you YET ANOTHER url in its return json.
Using the url returned from the previous step, you can link directly to that in the browser, and it'll take you to your track content. I checked on VLC by inputting the link and it streams correctly.
Hopefully this helps some of you out with your developing.
Since I have the same problem, the answer from #Default motivated me to look for a solution. But I did not understand the workaround with the permalink_url in the steps 2 and 3. The easier solution could be:
Fetch for example user track likes using api-v2 endpoint like this:
https://api-v2.soundcloud.com/users/<user_id>/track_likes?client_id=<client_id>
In the response we can finde the needed URL like mentioned from #Default in his answer:
collection: [
{
track: {
media: {
transcodings:[
...
{
url: "https://api-v2.soundcloud.com/media/soundcloud:tracks:713339251/0ab1d60e-e417-4918-b10f-81d572b862dd/stream/progressive"
...
}
]
}
}
...
]
Make request to this URL with client_id as a query param and you get another URL with that you can stream/download the track
Note that the api-v2 is still not public and the request from your client probably will be blocked by CORS.
As mentioned by #user208685 the solution can be a bit simpler by using the SoundCloud API v2:
Obtain the track ID (e.g. using the public API at https://developers.soundcloud.com/docs)
Get JSON from https://api-v2.soundcloud.com/tracks/TRACK_ID?client_id=CLIENT_ID
From JSON parse MP3 progressive stream URL
From stream URL get MP3 file URL
Play media from MP3 file URL
Note: This link is only valid for a limited amount of time and can be regenerated by repeating steps 3. to 5.
Example in node (with node-fetch):
const clientId = 'YOUR_CLIENT_ID';
(async () => {
let response = await fetch(`https://api.soundcloud.com/resolve?url=https://soundcloud.com/d-o-lestrade/gabriel-ananda-maceo-plex-solitary-daze-original-mix&client_id=${clientId}`);
const track = await response.json();
const trackId = track.id;
response = await fetch(`https://api-v2.soundcloud.com/tracks/${trackId}?client_id=${clientId}`);
const trackV2 = await response.json();
const streamUrl = trackV2.media.transcodings.filter(
transcoding => transcoding.format.protocol === 'progressive'
)[0].url;
response = await fetch(`${streamUrl}?client_id=${clientId}`);
const stream = await response.json();
const mp3Url = stream.url;
console.log(mp3Url);
})();
For a similar solution in Python, check this GitHub issue: https://github.com/soundcloud/soundcloud-python/issues/87

XmlHttpRequest not reporting server side progress

I have a client server application. The server side is completely in java. The client side has a few lines of html and the rest in plain javascript (I don't use ajax or jquery etc).
The client receives user inputs through an input box and when the user clicks a button, the client sends a POST request to the server using XmlHtpRequest. The server then runs a process that can take several minutes. The server periodically (every 5 seconds) sends a progress update message with HTTP status code 202 and with content "Processing.... completed 5 / 100". The numbers 5 and 100 are a sample. Instead of 100, it is the actual final counter of the process and instead of 5 it is the current counter indicating the progress. When the server finishes the processing it sends a 200 OK with the final output as the content. I have an output text area where I want to display the progress message during the processing and later the final output is also placed in the same output text area.
My client side javascript code is:
<script>
var xhr = new XmlHttpRequest();
function sendCommandToServer() {
window.xhr.onreadystatechange = getServerResponse;
window.xhr.open("POST", (document.domain + "/" + "executeCommand"), true);
window.xhr.send("arguments and data for the command");
}
</script>
<script>
function getServerResponse() {
if(window.xhr.status === 202) {
myTextArea.value = window.xhr.responseText;
window.xhr.onreadystatechange = getServerResponse;
return;
}
if(window.xhr.status === 200) {
myTextArea.value = window.xhr.responseText;
return;
}
alert("processing error");
}
</script>
The server correctly gets the command and runs the process and finishes and produces the output. It also correctly sends the progress messages. But my client side javascript does not get all of them. I am able to get the 1st progress message from the server - something like - "Processing .... 5 / 100" - but after that I am not able to get further calls to getServerResponse() to continue updating the progress as and when the server sends messages. If I modify the server side to avoid sending progress and send only the final output result, it works correctly and I get the final output result displayed at the client. I run this on IE10 and Chrome, with the same behavior. Can xmlHttpRequest() be used for this use-case? Am I doing something wrong? Any help will be appreciated. Thanks.
I'm new to this myself and trying to work out a method of achieving something similar.
I think the 202 status code is the only response you will get, ie the server will send a single response when it has accepted the job (202), or a 200 response when it has completed.
Source:
http://100pulse.com/http-statuscode/202.jsp