How to read multiple times from a bytes.Buffer? - http

I'm trying to create two HTTP requests with the same request body. Unfortunately, the second request sends an empty body.
w := httptest.NewRecorder()
w2 := httptest.NewRecorder()
pd := &postData{
Data: 5,
}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(pd)
req, _ := http.NewRequest("PUT", "/v1/jobs/echo", b)
server.ServeHTTP(w, req)
req, _ = http.NewRequest("PUT", "/v1/jobs/echo", b)
server.ServeHTTP(w2, req)
Reading through the documentation and the source code for bytes.Buffer, it looks like there's no way to reset the buffer to 0 - there's a Reset method, but this also wipes the buffer's internal state.
Is there a way to "replay" any reader in Go? A bytes.Buffer or any other Reader.

OK. So I wouldn't consider this ideal and it would be better to just init a reader in the first place but if you put your data in a bytes.Reader instead of bytes.Buffer then you'll be able to seek back to the beginning after the first call to NewRequest has read to the end.
w := httptest.NewRecorder()
w2 := httptest.NewRecorder()
pd := &postData{
Data: 5,
}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(pd)
r := bytes.NewReader(b.Bytes())
req, _ := http.NewRequest("PUT", "/v1/jobs/echo", r)
server.ServeHTTP(w, req)
r.Seek(0, 0)
req, _ = http.NewRequest("PUT", "/v1/jobs/echo", r)
server.ServeHTTP(w2, req)

Related

ESP8266 do not send back http resppond

I have some problem. If I have old firmware (NodeMCU 0.9.5 build 20150318 powered by Lua 5.1.4) then it works and I receive back response to phone. But if I have new one ( build 2022-09-07 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)) then I do not receive response (but I get request “who” on ESP8266). What is the problem it could be?
Code:
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
buf = buf.."HTTP/1.1 200 OK\n\n"
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if(method == nil)then
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
if(_GET.pin == "ON1")then
print(“On”)
elseif(_GET.pin == "OFF1") then
print(“Off”)
end
if(_GET.question == "who") then
buf=""
buf = buf.."HTTP/1.1 200 OK\n\n"
print(buf)
end
client:send(buf)
client:close()
collectgarbage()
end)
end)

http.get() returns "422 Unprocessable Entity"

I have written a go programme to query issues in github repository "golang:go".
The http.Get() responds with status "200 OK".
I then query for issues created in last 3 months and the http.Get() returns "422 Unprocessable Entity". Below is the programme
import(
"fmt"
"time"
"net/http"
"net/url"
)
func main() {
var ret error
var str string
q:=url.QueryEscape("repo:golang/go")
fmt.Println("q:", q)
urlStr := "https://api.github.com/search/issues" +"?q=" + q
fmt.Println("urlStr:", urlStr)
resp, ret:= http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
timeStr := "created:"
to := time.Now()
from := to.AddDate(0, -3, 0)
str = to.Format("2006-01-02")
timeStr = timeStr + str + ".."
fmt.Printf("time1 : %s\n", timeStr)
str = from.Format("2006-01-02")
timeStr = timeStr + str
fmt.Printf("time2 : %s\n", timeStr)
q=url.QueryEscape("repo:golang/go" + timeStr)
fmt.Println("q:", q)
urlStr = "https://api.github.com/search/issues" +"?q=" + q
fmt.Println("urlStr:", urlStr)
resp, ret = http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
}
I used this to form the query.
I am new to web programming and not able to understand where I went wrong in forming the second query.
two things that worked for me
1) reverse the "from" and "to" in your timeStr
2) don't use QueryEscape on the timeStr, just add it in like this
urlStr = "https://api.github.com/search/issues" + "?q=repo:golang/go+" + timeStr
Don't use an ampersand (I originally answered with this) use a plus sign or space. See https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-when-an-issue-or-pull-request-was-created-or-last-updated for the syntax
update: on further consideration the QueryEscape is a good idea! It seems coincidentally to "just work"
I used like the following and it works for me if i don't escape the 2nd url:
package main
import(
"fmt"
"time"
"net/http"
"net/url"
)
func main() {
var ret error
var str string
q:=url.QueryEscape("repo:golang/go")
fmt.Println("q:", q)
urlStr := "https://api.github.com/search/issues" +"?q=" + q
fmt.Println("urlStr:", urlStr)
resp, ret:= http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
timeStr := "created:"
to := time.Now()
from := to.AddDate(0, -3, 0)
str = to.Format("2006-01-02")
timeStr = timeStr + str + ".."
fmt.Printf("time1 : %s\n", timeStr)
str = from.Format("2006-01-02")
timeStr = timeStr + str
fmt.Printf("time2 : %s\n", timeStr)
urlStr = "https://api.github.com/search/issues" +"?q=" + "repo:golang/go&created:2018-11-29..2018-08-29"
fmt.Println("urlStr:", urlStr)
resp, ret = http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
}
And the output is:
q: repo%3Agolang%2Fgo
urlStr: https://api.github.com/search/issues?q=repo%3Agolang%2Fgo
ret : <nil> resp.status : 200 OK
time1 : created:2018-11-29..
time2 : created:2018-11-29..2018-08-29
urlStr: https://api.github.com/search/issues?q=repo:golang/go&created:2018-11-29..2018-08-29
ret : <nil> resp.status : 200 OK
Many APIs including the one from github return the 422 status code when the client sends invalid input. In your code the bad input is generated by the line that concatenates the two qualifiers without a "separator".
So this "repo:golang/go" + timeStr will result in the q value containing a single "merged" qualifier that looks something like this:
"repo:golang/gocreated:2018-1...
To fix your code you just need to add a space between the two qualifiers and your query should work.
q=url.QueryEscape("repo:golang/go " + timeStr)

how to get leetcode ranking with goquery

I want to get my leetcode ranking, But I know about html and JavaScript just a little. After a lot of try, I get this output.
aQuaYi's ranking is Ranking: {[{ pc.ranking }]}
source is
package main
import (
"fmt"
"log"
"github.com/PuerkitoBio/goquery"
)
func showRanking(username string) {
URL := fmt.Sprintf("https://leetcode.com/%s", username)
doc, err := goquery.NewDocument(URL)
if err != nil {
log.Fatal(err)
}
ranking, _ := doc.Find("div.panel-body").Find("span.ranking").Attr("data-content")
fmt.Printf("%s's ranking is %v", username, ranking)
}
func main() {
showRanking("aQuaYi")
}
Please help me finish this code, Thank you very much.
func getRanking(username string) string {
URL := fmt.Sprintf("https://leetcode.com/%s/", username)
fmt.Println(URL)
data := getRaw(URL) // or your way to get raw html page down
str := string(data)
i := strings.Index(str, "ng-init")
j := i + strings.Index(str[i:], "ng-cloak")
str = str[i:j]
i = strings.Index(str, "(")
j = strings.Index(str, ")")
str = str[i:j]
strs := strings.Split(str, ",")
ans := strs[5]
i = strings.Index(ans, "'")
j = 2 + strings.Index(ans[2:], "'")
return ans[i+1 : j]
}

One Esp8266 Client One Esp8266 Server

I did Server-Client Application with lua using one Esp8266. I wanna do this with two Esp8266. I wanna use one of these Esp8266 is Server and the other other one is Client. You can see below first code using for get RSSI from one AP and second code is using for writing these RSSI in a Server. How can i placed these two codes in two Esp8266?
i=5
tmr.alarm(1,10000,1, function()
print(wifi.sta.getap(scan_cfg, 1, listap))
if i>1 then
print(i)
i=i-1
else
tmr.stop(1)
print("Timer Durdu")
end
end
)
function listap(t)
for bssid,v in pairs(t) do
local ssid = string.match(v, "([^,]+)")
l=string.format("%-10s",ssid)
stringtoarray = {}
index = 1
for value in string.gmatch(v,"%w+") do
stringtoarray [index] = value
index = index + 1
end
print(l)
print(stringtoarray[2])
end
end
scan_cfg = {}
scan_cfg.ssid = "VSP250s"
scan_cfg.bssid = "00:09:df:8e:03:b4"
scan_cfg.channel = 0
scan_cfg.show_hidden = 1
Second code:
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if(method == nil)then
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
buf = buf.."<!DOCTYPE html><html><div id='container'><font size='5'>"
buf = buf..'<style>body{width:auto;height:auto;background-color:#ffffff;}'
buf = buf..'.button {font-size: 20px;}</style>'
buf = buf.."<head> <meta http-equiv='refresh' content=3> "
buf = buf.."<p><h1>RSSI meter<br> ESP8266</h1>";
--buf = buf.."<p>Refresh : <button class='button'>ON</button>&nbsp</p>";
--buf = buf.."<p>Relay Switch : <button class='button'>ON</button>  "
--buf = buf.."<button class='button'>OFF</button><br>"
buf = buf..'<B>Voltage :<font color=red>'..string.format('%s',l)..' V</font></b><br>'
buf = buf..'<B>Current :<B><font color=blue>'..string.format('%g',stringtoarray[2])..' A</font></b><br>'
--buf = buf..'<B>Power Consumption :<B><font color=DeepSkyBlue>'..'Not Available'..'</font></b><br><BR>'
-- buf = buf..'<p>Function Button :<B><font color=BlueViolet>'..button_status..'</font></b><br></p>';
buf = buf..'</head>'
buf = buf..'<br><br><details><summary><font color=red>BURAK IPEK</font><p>'
buf = buf..'<summary><p>Vestel Electronics </p></details>'
buf = buf.."</body></font></div></html>"
client:send(buf);
client:close();
collectgarbage();
end)
end)
Put each code into a lua file. Include both from init.lua with typing
dofile("client.lua");
dofile("server.lua");
To make things easier, write methods.
Good luck.

Convert map[interface {}]interface {} to map[string]string

From a source I cannot influence I am given data in a map, which arrives as map[interface {}]interface {}.
I need to process the contained data, preferably as map[string]string (the data within is perfectly suitable for that).
I need to generate a list of the keys from the data as well, as those are not known beforehand.
Most similar questions I could find on the web say more or less, that this is impossible, but if my map is m, fmt.Println(m) shows the data is there, readable as map[k0:v0 K1:v1 k2:v2 ... ].
How can I do what fmt.Println is able to do?
A secure way to process unknown interfaces, just use fmt.Sprintf()
https://play.golang.org/p/gOiyD4KpQGz
package main
import (
"fmt"
)
func main() {
mapInterface := make(map[interface{}]interface{})
mapString := make(map[string]string)
mapInterface["k1"] = 1
mapInterface[3] = "hello"
mapInterface["world"] = 1.05
for key, value := range mapInterface {
strKey := fmt.Sprintf("%v", key)
strValue := fmt.Sprintf("%v", value)
mapString[strKey] = strValue
}
fmt.Printf("%#v", mapString)
}
Perhaps I misunderstand the question, but would this work?
m := make(map[interface{}]interface{})
m["foo"] = "bar"
m2 := make(map[string]string)
for key, value := range m {
switch key := key.(type) {
case string:
switch value := value.(type) {
case string:
m2[key] = value
}
}
}
// data is map[string]interface{}
form := make(map[string]string)
for k, v := range data {
form[k] = v.(string)
}

Resources