golang get domain from email using parse standard library - parsing

I'm having trouble pulling out the domain for emails. I've tried using variations of
u, _ := url.Parse(email)
and other parsing from the standard library, but nothing that seems to parse: user#gmail.com into separate parts.
I've also tried net.SplitHostPort with no luck.
I don't want to get create a function which gets the len and separate to get substring after # symbol if possible.
Does anyone have any ideas to do this?
Thanks!

Here's an example I concocted from the golang documentation:
package main
import (
"fmt"
"strings"
)
func main() {
email := "foo#bar.com"
components := strings.Split(email, "#")
username, domain := components[0], components[1]
fmt.Printf("Username: %s, Domain: %s\n", username, domain)
}
UPDATE: 2020-09-01 - updating to use last # sign per #Kevin's feedback in the comments.
package main
import (
"fmt"
"strings"
)
func main() {
email := "foo#bar.com"
at := strings.LastIndex(email, "#")
if at >= 0 {
username, domain := email[:at], email[at+1:]
fmt.Printf("Username: %s, Domain: %s\n", username, domain)
} else {
fmt.Printf("Error: %s is an invalid email address\n", email)
}
}
Here are some tests: https://play.golang.org/p/cg4RqZADLml

Related

Go url.Parse(string) fails with certain user names or passwords

Using a URL that has worked in the past, I know receive a parsing error from net/url. What's wrong with it?
parse postgres://user:abc{DEf1=ghi#example.com:5432/db?sslmode=require: net/url: invalid userinfo
Sample application
See https://play.golang.com/p/mQZaN5JN3_q to run.
package main
import (
"fmt"
"net/url"
)
func main() {
dsn := "postgres://user:abc{DEf1=ghi#example.com:5432/db?sslmode=require"
u, err := url.Parse(dsn)
fmt.Println(u, err)
}
Well, you can just
url.QueryEscape("your#$%^&*(proper$#$%%^(password")
and use this one to parse your url.
It turns out up until Go v1.9.3 net/url didn't validate the user info when parsing a url. This may break existing applications when compiled using v1.9.4 if the username or password contain special characters.
It now expects the user info to be percent encoded string in order to handle special characters. The new behaviour got introduced in ba1018b.
Fixed sample application
package main
import (
"fmt"
"net/url"
)
func main() {
dsn1 := "postgres://user:abc{DEf1=ghi#example.com:5432/db?sslmode=require" // this works up until 1.9.3 but no longer in 1.9.4
dsn2 := "postgres://user:abc%7BDEf1=ghi#example.com:5432/db?sslmode=require" // this works everywhere, note { is now %7B
u, err := url.Parse(dsn1)
fmt.Println("1st url:\t", u, err)
u, err = url.Parse(dsn2)
fmt.Println("2nd url:\t", u, err)
}
Run the code on https://play.golang.com/p/jGIQgbiKZwz.
Use url.UserPassword func :
package main
import (
"fmt"
"net/url"
)
func main() {
dsn := "postgres://example.com:5432/db?sslmode=require"
u, err := url.Parse(dsn)
if err != nil {
fmt.Printf("ERROR: %v\n", err)
return
}
u.User = url.UserPassword("user", "abc{DEf1=ghi")
fmt.Println("url:\t", u)
}

Golang HTTPS/TLS POST client/server

I have written a simple client/server in Go that will do an HTTP GET over TLS, but I'm trying to also make it capable of doing an HTTP POST over TLS.
In the example below index.html just contains the text hello, and the HTTP GET is working fine. I want the client to get the HTTP GET and write back, hello world to the server.
client
package main
import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func main() {
link := "https://10.0.0.1/static/index.html"
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
response, err := client.Get(link)
if err != nil {
fmt.Println(err)
}
defer response.Body.Close()
content, _ := ioutil.ReadAll(response.Body)
s := strings.TrimSpace(string(content))
fmt.Println(s)
// out := s + " world"
// Not working POST...
// resp, err := client.Post(link, "text/plain", &out)
}
server
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/static/", func (w http.ResponseWriter, r *http.Request) {
fmt.Println("Got connection!")
http.ServeFile(w, r, r.URL.Path[1:])
})
log.Fatal(http.ListenAndServeTLS(":443", "server.crt", "server.key", nil))
}
I also currently have nothing to handle the POST on the server side, but I just want it to print it out to the screen so when I run the client I will see the server print hello world.
How should I fix my client code to do a proper POST? And what should the corresponding server code look like to accept the POST? Any help would be appreciated, I'm having trouble finding HTTPS/TLS POST examples.
You didn't share the error message, but I assume the client.Post call wasn't allowing a string as its third parameter, because it requires an io.Reader. Try this instead:
out := s + " world"
resp, err := client.Post(link, "text/plain", bytes.NewBufferString(out))
On the server side, you already have the right code set up to handle the POST request. Just check the method:
http.HandleFunc("/static/", func (w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
// handle POST requests
} else {
// handle all other requests
}
})
I noticed one other issue. Using index.html probably won't work here. http.ServeFile will redirect that path. See https://golang.org/pkg/net/http/#ServeFile:
As a special case, ServeFile redirects any request where r.URL.Path
ends in "/index.html" to the same path, without the final
"index.html". To avoid such redirects either modify the path or use
ServeContent.
I'd suggest just using a different file name to avoid that issue.

Is there a way to expand shortened URLs in Go [duplicate]

So, I'm using the net/http package. I'm GETting a URL that I know for certain is redirecting. It may even redirect a couple of times before landing on the final URL. Redirection is handled automatically behind the scenes.
Is there an easy way to figure out what the final URL was without a hackish workaround that involves setting the CheckRedirect field on a http.Client object?
I guess I should mention that I think I came up with a workaround, but it's kind of hackish, as it involves using a global variable and setting the CheckRedirect field on a custom http.Client.
There's got to be a cleaner way to do it. I'm hoping for something like this:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
// Try to GET some URL that redirects. Could be 5 or 6 unseen redirections here.
resp, err := http.Get("http://some-server.com/a/url/that/redirects.html")
if err != nil {
log.Fatalf("http.Get => %v", err.Error())
}
// Find out what URL we ended up at
finalURL := magicFunctionThatTellsMeTheFinalURL(resp)
fmt.Printf("The URL you ended up at is: %v", finalURL)
}
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
resp, err := http.Get("http://stackoverflow.com/q/16784419/727643")
if err != nil {
log.Fatalf("http.Get => %v", err.Error())
}
// Your magic function. The Request in the Response is the last URL the
// client tried to access.
finalURL := resp.Request.URL.String()
fmt.Printf("The URL you ended up at is: %v\n", finalURL)
}
Output:
The URL you ended up at is: http://stackoverflow.com/questions/16784419/in-golang-how-to-determine-the-final-url-after-a-series-of-redirects
I would add a note that http.Head method should be enough to retrieve the final URL. Theoretically it should be faster comparing to http.Get as a server is expected to send back just a header:
resp, err := http.Head("http://stackoverflow.com/q/16784419/727643")
...
finalURL := resp.Request.URL.String()
...

Parsing a golang time object from an incomplete string

I have the following date string: 2017-09-04T04:00:00Z
I need to parse this string into a golang time in order to have uniform data across my application. Here is the code so far:
parsedTime := "2017-09-04T04:00:00Z"
test, err := time.Parse(time.RFC3339, parsedTime)
check(err)
fmt.Println(test)
I get the following error when I try to run the program:
": extra text: 0:00 +0000 UTC parsing time "2017-09-04T04:00:00Z
How can I either add the extra text that it is looking for or get the parser to stop looking after the Z?
I have also tried the following:
parsedTime := "2017-09-04T04:00:00Z"
test, err := time.Parse("2006-01-02T03:04:05Z", parsedTime)
check(err)
fmt.Println(test)
Which returns the following error:
": extra text: 017-09-04T04:00:00Z
Both formats you used work with the current version of go: https://play.golang.org/p/Typyq3Okrd
var formats = []string{
time.RFC3339,
"2006-01-02T03:04:05Z",
}
func main() {
parsedTime := "2017-09-04T04:00:00Z"
for _, format := range formats {
if test, err := time.Parse(format, parsedTime); err != nil {
fmt.Printf("ERROR: format %q resulted in error: %v\n", format, err)
} else {
fmt.Printf("format %q yielded %s\n", format, test)
}
}
}
Can you provide a working example that demonstrates your problem? You can use the go playground for shareable snippets.

Passing flag variable to go program causing strange output

sergiotapia at Macbook-Air in ~/Work/go/src/github.com/sergiotapia/gophers on master [!]
$ go build && go install && gophers -github_url=https://github.com/search?utf8=%E2%9C%93&q=location%3A%22San+Fransisco%22+location%3ACA+followers%3A%3E100&type=Users&ref=advsearch&l=
[1] 51873
[2] 51874
[3] 51875
[4] 51877
[2] Done q=location%3A%22San+Fransisco%22+location%3ACA+followers%3A%3E100
[3] Done type=Users
[4]+ Done ref=advsearch
I'm trying to use the long github url as a parameter in my code for Gophers. It works fine for all other url types such as organisations or stargazers. However when I try to use the search results page I get the strange output above.
https://github.com/search?utf8=%E2%9C%93&q=location%3A%22San+Fransisco%22+location%3ACA+followers%3A%3E100&type=Users&ref=advsearch&l=
package main
import (
"flag"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
type user struct {
name string
email string
url string
username string
}
func main() {
url := flag.String("github_url", "", "github url you want to scrape")
flag.Parse()
githubURL := *url
doc, err := goquery.NewDocument(githubURL)
if err != nil {
log.Fatal(err)
}
if strings.Contains(githubURL, "/orgs/") {
scrapeOrganization(doc, githubURL)
} else if strings.Contains(githubURL, "/search?") {
scrapeSearch(doc, githubURL)
} else if strings.Contains(githubURL, "/stargazers") {
scrapeStarGazers(doc, githubURL)
} else {
scrapeProfile(doc)
}
}
It's a bash command line (or whatever the mac uses). & and ? are shell metacharacters that you MUST escape. The shell has absolutely no idea what a URL is, nor should it ever have to.
go 'http://....'
^-----------^
Adding quotes will prevent the shell from parsing the metacharacters. The alternative is to manually escape each and ever metachar yourself:
go http://example.com/script.php\?foo=bar\&baz=qux
^--------^
which quickly gets tedious, and error prone.

Resources