summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README.md42
-rw-r--r--go.mod5
-rw-r--r--go.sum2
-rw-r--r--main.go93
5 files changed, 143 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9ecece9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+ght
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c712269
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+# ght
+go-http-get
+
+## Build
+Please check if the Go path is running.
+```bash
+which go
+```
+
+And then compile.
+```bash
+go build -o ght main.go
+```
+Move the executable binary to `/usr/local/bin` to work with CLI.
+```bash
+sudo mv ght /usr/local/bin
+sudo chown root:root /usr/local/bin/ght
+which ght
+```
+
+## Usage
+URL in `$1`.
+```bash
+$ ght
+Usage: ght "https://google.com/"
+```
+
+### for example
+If you have a file called `urls` with URLs listed.
+```bash:urls
+https://www.google.com/
+https://soulminingrig.com/
+https://soulminingrig.com/ab/
+```
+Single proccessing
+```bash
+cat urls | while read -r url ; do ght $url ; done
+```
+Parallel processing with `xargs`
+```bash
+cat urls | xargs -P 4 -I {} ght {}
+```
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..188e966
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module ght
+
+go 1.23.3
+
+require golang.org/x/net v0.31.0
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..26142d0
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
+golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..903abc4
--- /dev/null
+++ b/main.go
@@ -0,0 +1,93 @@
+package main
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net/http"
+ "os"
+ "time"
+
+ "golang.org/x/net/html"
+)
+
+func findTitleTag(n *html.Node) string {
+ if n.Type == html.ElementNode && n.Data == "title" {
+ if n.FirstChild != nil {
+ return n.FirstChild.Data
+ }
+ }
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if result := findTitleTag(c); result != "" {
+ return result
+ }
+ }
+ return ""
+}
+
+func fetchAndParse(client *http.Client, url string, useRange bool) (string, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return "", fmt.Errorf("failed to create request: %w", err)
+ }
+ if useRange {
+ req.Header.Set("Range", "bytes=0-4096")
+ }
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("failed to fetch URL: %w", err)
+ }
+ defer resp.Body.Close()
+
+ doc, err := html.Parse(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to parse HTML: %w", err)
+ }
+
+ return findTitleTag(doc), nil
+}
+
+func fetchTitle(url string) (string, error) {
+ client := &http.Client{
+ Timeout: 5 * time.Second,
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ },
+ }
+
+ // range limit : get request
+ title, err := fetchAndParse(client, url, true)
+ if err != nil {
+ return "", err
+ }
+ if title != "" {
+ return title, nil
+ }
+
+ // no range limit : get reqest
+ title, err = fetchAndParse(client, url, false)
+ if err != nil {
+ return "", err
+ }
+ if title == "" {
+ return "", fmt.Errorf("no title found: %s", url)
+ }
+
+ return title, nil
+}
+
+func main() {
+ if len(os.Args) < 2 {
+ fmt.Fprintln(os.Stderr, "Usage: ght \"https://google.com/\"")
+ os.Exit(1)
+ }
+
+ url := os.Args[1]
+ title, err := fetchTitle(url)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+ os.Exit(2)
+ }
+
+ fmt.Printf("%s\n", title)
+}