core.go 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. package main
  2. import (
  3. "database/sql"
  4. "fmt"
  5. _ "github.com/go-sql-driver/mysql"
  6. "html"
  7. "html/template"
  8. "io/ioutil"
  9. "log"
  10. "net/http"
  11. "net/url"
  12. "strconv"
  13. "strings"
  14. "unicode/utf8"
  15. // "sync"
  16. // "time"
  17. )
  18. type indexPage struct{}
  19. type errorReport struct{ Error string }
  20. type surpriseURL struct{ Url string }
  21. type settingsPage struct{ Worksafe, FilterHTTPS bool }
  22. type MySQLResults struct{ Id, Url, Title, Description, Body string }
  23. type PageData struct {
  24. DBResults []MySQLResults
  25. Query, Page string
  26. FindMore bool
  27. }
  28. func main() {
  29. http.HandleFunc("/", handler)
  30. http.HandleFunc("/json", handler)
  31. http.HandleFunc("/json/", handler)
  32. http.HandleFunc("/surprise", surprise)
  33. http.HandleFunc("/surprise/", surprise)
  34. http.HandleFunc("/settings/", settings)
  35. http.HandleFunc("/settings", settings)
  36. log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil)) //set IP to localhost if reverse proxy is on the same machine
  37. }
  38. //https://golang.org/pkg/net/http/#Request
  39. func handler(w http.ResponseWriter, r *http.Request) {
  40. //fmt.Fprintf(w, "%s %s \n", r.Method, r.URL)
  41. //fmt.Fprintf(w, "%s \n", r.URL.RawQuery)
  42. //Indicate whether or not you are using shard tables
  43. shards := true
  44. //check if worksafe+https cookie enabled.
  45. filterHTTPS := false
  46. worksafe := true
  47. worksafeHTTPSCookie, err := r.Cookie("ws")
  48. if err != nil {
  49. worksafe = true
  50. filterHTTPS = false
  51. } else if worksafeHTTPSCookie.Value == "0" {
  52. worksafe = false
  53. filterHTTPS = false
  54. } else if worksafeHTTPSCookie.Value == "1" {
  55. worksafe = true
  56. filterHTTPS = false
  57. } else if worksafeHTTPSCookie.Value == "2" {
  58. worksafe = false
  59. filterHTTPS = true
  60. } else if worksafeHTTPSCookie.Value == "3" {
  61. worksafe = true
  62. filterHTTPS = true
  63. }
  64. //setup for error report
  65. error := errorReport{}
  66. //Get the raw query
  67. m, _ := url.ParseQuery(r.URL.RawQuery)
  68. //Get the query parameters (q and o)
  69. //fmt.Fprintf(w,"%s\n%s\n", m["q"][0], m["o"][0])
  70. json := false
  71. if strings.Contains(r.URL.Path, "/json") {
  72. json = true
  73. if _, ok := m["nsfw"]; ok { //check if &nsfw added to json url
  74. worksafe = false
  75. }
  76. }
  77. query := ""
  78. queryNoQuotes := ""
  79. offset := "0"
  80. page := "0"
  81. //Check if query and page params exist
  82. if _, ok := m["q"]; ok {
  83. query = m["q"][0]
  84. query = strings.Replace(query, "'", "''", -1)
  85. query = strings.Replace(query, "+ ", " ", -1)
  86. query = strings.Replace(query, "- ", " ", -1)
  87. queryNoQuotes = query
  88. }
  89. if _, ok := m["p"]; ok {//gets page num, will convert to offset further down
  90. page = m["p"][0]
  91. page = strings.Replace(page, "'", "''", -1)
  92. offset = page
  93. }
  94. lim := "12"
  95. // limDistributedInt :=
  96. if query == "" { //what do if no query found?
  97. //load index if no query detected
  98. if r.URL.Path == "/" {
  99. p := indexPage{}
  100. t, _ := template.ParseFiles("coreassets/form.html.go")
  101. t.Execute(w, p)
  102. } else if strings.Contains(r.URL.Path, "/json") { //load json info page if json selected
  103. p := indexPage{}
  104. t, _ := template.ParseFiles("coreassets/json/json.html.go")
  105. t.Execute(w, p)
  106. } else {
  107. p := indexPage{}
  108. t, _ := template.ParseFiles("coreassets/form.html.go")
  109. t.Execute(w, p)
  110. }
  111. } else {
  112. //Make sure offset is a number
  113. offsetInt, err := strconv.Atoi(offset)
  114. if err != nil {
  115. offset = "0"
  116. offsetInt = 0
  117. }
  118. //Make sure page is a number
  119. pageInt, err := strconv.Atoi(page)
  120. if err != nil {
  121. page = "0"
  122. pageInt = 0
  123. }
  124. //Convert lim to number
  125. limInt, _ := strconv.Atoi(lim)
  126. //convert page num to offset
  127. if offsetInt > 0 {
  128. offsetInt --;
  129. }
  130. offsetInt = offsetInt * limInt
  131. offset = strconv.Itoa(offsetInt)
  132. //get some details from the raw query
  133. var additions string
  134. querylen := len(query)
  135. //see if a search redirect (! or &) is used for a different search engine
  136. if json == false && (strings.Contains(m["q"][0],"!") || strings.Contains(m["q"][0],"&")){
  137. searchredirect(w, r, m["q"][0])
  138. }
  139. //phone users
  140. if query[querylen-1] == ' '{
  141. query = query[:querylen-1]
  142. queryNoQuotes = queryNoQuotes[:len(queryNoQuotes)-1]
  143. querylen = len(query)
  144. }
  145. if querylen > 1 && query[0] == ' '{
  146. query = query[1:querylen]
  147. queryNoQuotes = queryNoQuotes[1:len(queryNoQuotes)]
  148. querylen = len(query)
  149. }
  150. //check if user wants to limit search to a specific website
  151. sitePos := -1
  152. siteEnd := 0
  153. siteURL := ""
  154. if strings.Index(strings.ToLower(query), "site:") > -1 {
  155. //get url user wants to search and remove it from the query string
  156. sitePos = strings.Index(strings.ToLower(query), "site:")
  157. siteEnd = strings.Index(query[sitePos:], " ")
  158. //fmt.Printf("\n%d\n%d\n",sitePos,siteEnd)
  159. if siteEnd > -1 && sitePos > 1 { //site is not last part of query
  160. siteURL = query[sitePos+5 : siteEnd+sitePos]
  161. query = query[:sitePos-1] + query[siteEnd+sitePos:]
  162. queryNoQuotes = queryNoQuotes[:sitePos-1] + queryNoQuotes[siteEnd+sitePos:]
  163. additions = additions + "AND url LIKE '%" + siteURL + "%' "
  164. } else if siteEnd > -1 && sitePos == 0 { //site is at beginning
  165. siteURL = query[sitePos+5 : siteEnd]
  166. query = query[siteEnd+1:]
  167. queryNoQuotes = queryNoQuotes[siteEnd+1:]
  168. additions = additions + "AND url LIKE '%" + siteURL + "%' "
  169. } else if siteEnd < 0 && sitePos > 1 { //site is at end
  170. siteURL = query[sitePos+5:]
  171. query = query[:sitePos-1]
  172. queryNoQuotes = queryNoQuotes[:sitePos-1]
  173. additions = additions + "AND url LIKE '%" + siteURL + "%' "
  174. }else if querylen > 5{
  175. query = query[5:]
  176. }
  177. querylen = len(query)
  178. }
  179. //fmt.Printf("Addition: \n%s\nQuery: '%s'\n",additions,query)
  180. //see if user uses -https flag (instead of cookie settings option)
  181. if querylen > 7 && strings.ToLower(query[querylen-7:querylen]) == " -https" {
  182. filterHTTPS = true
  183. query = query[0 : querylen-7]
  184. querylen = len(query)
  185. }
  186. //check if user wants to search within a time window (day,week,month)
  187. option := ""
  188. //fmt.Printf("\n'%s'\n",query)
  189. location := strings.Index(query, " !")
  190. if location == -1 {
  191. location = strings.Index(query, " &")
  192. }
  193. if location > -1 && strings.Index(query[location+1:querylen], " ") == -1 { //option is at end of query
  194. option = query[location+2 : querylen]
  195. query = query[:location]
  196. queryNoQuotes = queryNoQuotes[:location]
  197. querylen = len(query)
  198. }else if querylen > 0 && (query[0] == '!' || query[0] == '&') && strings.Index(query, " ") > -1{ //option is at start of query
  199. option = query[1:strings.Index(query, " ")]
  200. query = query[strings.Index(query, " ")+1:]
  201. queryNoQuotes = queryNoQuotes[strings.Index(queryNoQuotes, " ")+1:]
  202. querylen = len(query)
  203. }
  204. option = strings.ToLower(option)
  205. if option != "" {
  206. if option == "td" { //day
  207. additions = additions + "AND date > NOW() - INTERVAL 1 DAY "
  208. } else if option == "tw" { //week
  209. additions = additions + "AND date > NOW() - INTERVAL 7 DAY "
  210. } else if option == "tm" { //month
  211. additions = additions + "AND date > NOW() - INTERVAL 30 DAY "
  212. } else if option == "ty" { //year
  213. additions = additions + "AND date > NOW() - INTERVAL 365 DAY "
  214. }
  215. }
  216. //check if worksafe and filterHTTPS flags set
  217. if worksafe == true {
  218. additions = additions + "AND worksafe = '1' "
  219. }
  220. if filterHTTPS == true {
  221. additions = additions + "AND http = '1' "
  222. }
  223. //search if query has quotes and remove them (so we can find the longest word in the query)
  224. exactMatch := false
  225. //queryNoQuotes := query
  226. if strings.Contains(query, "\"") {
  227. exactMatch = true
  228. queryNoQuotes = strings.TrimLeft(queryNoQuotes, "\"")
  229. getlastquote := strings.Split(queryNoQuotes, "\"")
  230. queryNoQuotes = getlastquote[0]
  231. //fmt.Printf("%s \n", queryNoQuotes)
  232. }
  233. //remove the '*' if contained anywhere in queryNoQuotes
  234. if strings.Contains(queryNoQuotes, "*") && exactMatch == false {
  235. queryNoQuotes = strings.Replace(queryNoQuotes, "*", "", -1)
  236. }
  237. //Prepare to find longest word in query
  238. words := strings.Split(queryNoQuotes, " ")
  239. longestWordLength := 0
  240. longestWord := ""
  241. wordcount := 0
  242. longestwordelementnum := 0
  243. queryNoQuotesOrFlags := queryNoQuotes
  244. requiredword := ""
  245. flags := ""
  246. flagssetbyuser := 0
  247. wordlen := 0
  248. numRequiredWords := 0
  249. //queryNoFlags := ""
  250. //first remove any flags inside var queryNoQuotes, also grab any required words (+ prefix)
  251. if strings.Contains(queryNoQuotes, "-") || strings.Contains(queryNoQuotes, "+") {
  252. queryNoQuotesOrFlags = ""
  253. for i, wordNoFlags := range words {
  254. if i > 0 && strings.HasPrefix(wordNoFlags, "-") == false && strings.HasPrefix(wordNoFlags, "+") == false { //add a space after
  255. queryNoQuotesOrFlags += " "
  256. }
  257. if strings.HasPrefix(wordNoFlags, "-") == false && strings.HasPrefix(wordNoFlags, "+") == false {
  258. queryNoQuotesOrFlags += wordNoFlags
  259. }
  260. if strings.HasPrefix(wordNoFlags, "+") == true && len(wordNoFlags) > 1 && requiredword == "" { //get requiredword
  261. requiredword = wordNoFlags[1:len(wordNoFlags)]
  262. }
  263. if i > 0 && strings.HasPrefix(wordNoFlags, "-") == true || strings.HasPrefix(wordNoFlags, "+") == true {
  264. flags += " " + wordNoFlags
  265. flagssetbyuser++
  266. if strings.HasPrefix(wordNoFlags, "+") == true {
  267. numRequiredWords++
  268. }
  269. }
  270. }
  271. }
  272. //now find longest word, and build extra locate statements for partial matches (when sorting results returned from replicas)
  273. partialLocate := ""
  274. locateWords := false
  275. words = strings.Split(queryNoQuotesOrFlags, " ")
  276. if exactMatch == false {
  277. for _, word := range words {
  278. if len(word) > longestWordLength {
  279. longestWordLength = len(word)
  280. longestWord = word
  281. longestwordelementnum = wordcount
  282. }
  283. if wordcount < 5 && len(word) > 3{
  284. if locateWords == false {
  285. partialLocate += " WHEN LOCATE('" + word + "', title) "
  286. }else{
  287. partialLocate += "OR LOCATE('" + word + "', title) "
  288. }
  289. locateWords=true
  290. }
  291. if word != ""{
  292. wordcount++
  293. }
  294. }
  295. if locateWords == true{
  296. partialLocate += "THEN 10"
  297. }
  298. }
  299. //fmt.Printf("\n%s",partialLocate)
  300. //create another query where all compatible words are marked as keywords
  301. reqwordQuery := ""
  302. for i, word := range words{
  303. wordlen = len(word)
  304. if i==0 && (strings.HasPrefix(word, "+") == true || strings.HasPrefix(word, "-") == true) && wordlen > 3{
  305. reqwordQuery += word
  306. }
  307. if i==0 && (strings.HasPrefix(word, "+") == false && strings.HasPrefix(word, "-") == false) {
  308. if wordlen > 2 {
  309. reqwordQuery += "+"
  310. }
  311. reqwordQuery += word
  312. }
  313. if i!=0 && (strings.HasPrefix(word, "+") == true || strings.HasPrefix(word, "-") == true) && wordlen > 3{
  314. reqwordQuery += " "
  315. reqwordQuery += word
  316. }
  317. if i!=0 && (strings.HasPrefix(word, "+") == false && strings.HasPrefix(word, "-") == false) {
  318. reqwordQuery += " "
  319. if wordlen > 2 {
  320. reqwordQuery += "+"
  321. }
  322. reqwordQuery += word
  323. }
  324. }
  325. reqwordQuery += flags
  326. //fmt.Fprintf(w,"%s\n%s\n", query,offset)
  327. //fmt.Printf("hai\n")
  328. //get copy of original query because we might have to modify it somewhat
  329. queryOriginal := query
  330. tRes := MySQLResults{}
  331. var res = PageData{}
  332. //Check if query is a url.
  333. urlDetected := false
  334. isURL := ""
  335. isURLlocate := ""
  336. if strings.Index(query, " ") == -1 && strings.Index(query, "\"") == -1 && strings.Index(query, ".") > -1 { //note this will also flag on file extensions
  337. if len(query) > 6 && (query[0:7] == "http://" || query[0:7] == "HTTP://") {
  338. query = query[7:]
  339. } else if len(query) > 7 && (query[0:8] == "https://" || query[0:8] == "HTTPS://") {
  340. query = query[8:]
  341. }
  342. if len(queryNoQuotes) > 6 && (queryNoQuotes[0:7] == "http://" || queryNoQuotes[0:7] == "HTTP://") {
  343. queryNoQuotes = queryNoQuotes[7:]
  344. } else if len(queryNoQuotes) > 7 && (queryNoQuotes[0:8] == "https://" || queryNoQuotes[0:8] == "HTTPS://") {
  345. queryNoQuotes = queryNoQuotes[8:]
  346. }
  347. query = "\"" + query + "\""
  348. urlDetected = true
  349. isURL = "WHEN MATCH(url) AGAINST('\"" + queryNoQuotes + "\"' IN BOOLEAN MODE) THEN 25"
  350. isURLlocate = "WHEN LOCATE('" + queryNoQuotesOrFlags + "', url) THEN 25"
  351. }
  352. //Check if query contains a hyphenated word. Will wrap quotes around hyphenated words that aren't part of a string which is already wraped in quotes.
  353. if (strings.Contains(queryNoQuotes, "-") || strings.Contains(queryNoQuotes, "+")) && urlDetected == false {
  354. hyphenwords := strings.Split(query, " ")
  355. query = ""
  356. quotes := 0
  357. for i, word := range hyphenwords {
  358. if strings.Contains(word, "\"") {
  359. quotes++
  360. }
  361. if ((strings.Contains(word, "-") && word[0] != '-') || (strings.Contains(word, "+") && word[0] != '+')) && quotes%2 == 0 { //if hyphen or plus exists, not a flag, not wrapped in quotes already
  362. word = "\"" + word + "\""
  363. }
  364. if i > 0 {
  365. query += " "
  366. }
  367. query += word
  368. }
  369. }
  370. //fmt.Printf(">%s<\n", query)
  371. //if no required words set, make the longest word in the query required.
  372. querywithrequiredword := ""
  373. if numRequiredWords == 0 && wordcount > 1 && longestWordLength > 2{
  374. querywithrequiredword = query + " +"
  375. querywithrequiredword = querywithrequiredword + longestWord
  376. }
  377. //perform full text search FOR InnoDB or MyISAM
  378. var sqlQuery, id, url, title, description, body, idList string
  379. rangeOffset := 0
  380. serverCount := 0
  381. var servers []string
  382. numServers := 0
  383. //parse res.csv
  384. noservers := false
  385. repLim, _ := strconv.Atoi(lim)
  386. repOffset, _ := strconv.Atoi(offset)
  387. repLimStr := ""
  388. repOffsetStr := ""
  389. shard := ""
  390. noresults := 0
  391. repsearchfail := 0
  392. var idListChans []chan string
  393. oneword := false
  394. if strings.Index(query, " ") == -1{
  395. oneword = true
  396. }
  397. resourceFile, err := ioutil.ReadFile("res.csv")
  398. if err != nil {
  399. noservers = true
  400. } else {
  401. if len(resourceFile) < 2 {
  402. noservers = true
  403. }
  404. }
  405. //this switches off use of multiple connections to process a one word query. Should remove this if the database grows significantly larger
  406. /*if strings.Contains(query, " ") == false && oneletterquery == 0 {
  407. noservers = true
  408. }*/
  409. queryWithQuotesAndFlags := "\"" + queryNoQuotesOrFlags + "\"" + flags
  410. //if query is just 1 or 2 letters, help make it work.
  411. if utf8.RuneCountInString(queryOriginal) < 3 {
  412. queryfix := "" + query + "*"
  413. query = queryfix
  414. queryWithQuotesAndFlags = queryfix
  415. reqwordQuery = queryfix
  416. }
  417. if strings.Contains(queryOriginal,"c++")==true || strings.Contains(queryOriginal,"C++")==true{ // :) :( :) :(
  418. exactMatch=true
  419. queryWithQuotesAndFlags += " +programming"
  420. if strings.Contains(queryOriginal," ")==true && longestWordLength>3{
  421. queryWithQuotesAndFlags += " +"
  422. queryWithQuotesAndFlags += longestWord
  423. }
  424. }
  425. querytouse := query
  426. if querywithrequiredword != ""{
  427. querytouse = querywithrequiredword
  428. }else if numRequiredWords > 0{
  429. querytouse = reqwordQuery
  430. }
  431. reqwordQuery_filtered := strings.Replace(reqwordQuery, "'", "", -1)
  432. //For a less restrictive search, replace only the first instance of reqwordQuery_filtered with querytouse_filtered in the SQL query used when calling the distributedQuery go routine
  433. querytouse_filtered := strings.Replace(querytouse, "'", "", -1)
  434. queryWithQuotesAndFlags_filtered := strings.Replace(queryWithQuotesAndFlags, "'", "", -1)
  435. if noservers == false {
  436. //send query to go routines.
  437. resourceFilestring := string(resourceFile)
  438. //just in case user is messing around res.csv with a text editor and the editor ads a line feed to the end of the file
  439. if len(resourceFilestring) > 0 && resourceFilestring[len(resourceFilestring)-1] == byte('\n') {
  440. resourceFilestring = resourceFilestring[0 : len(resourceFilestring)-1]
  441. }
  442. servers = strings.Split(resourceFilestring, "\n")
  443. numServers = len(servers)
  444. if(shards == false){
  445. //numServers must divide evenly into lim, or lim must divide evenly into numservers
  446. //if they do not, automatically adjust numServers until they divide evenly
  447. //calculate number of servers to use based on lim size
  448. if limInt > numServers {
  449. for limInt%numServers > 0 {
  450. numServers -= 1
  451. }
  452. } else if numServers > limInt {
  453. for numServers%limInt > 0 {
  454. numServers -= 1
  455. }
  456. }
  457. }
  458. //calculate limit and offset on distributed servers.
  459. if numServers < limInt {
  460. repLim = limInt / numServers
  461. } else {
  462. repLim = 1
  463. }
  464. repOffset = offsetInt / numServers
  465. //calculate rangeOffset (offset for the range of returned results, important if numServers > 2*lim)
  466. rangeOffset = offsetInt - (repOffset * numServers)
  467. repLimStr = strconv.Itoa(repLim)
  468. repOffsetStr = strconv.Itoa(repOffset)
  469. //create a channel for each available server
  470. for i := 0; i < numServers; i++ {
  471. idListChans = append(idListChans, make(chan string))
  472. }
  473. for _, server := range servers {
  474. serverSettings := strings.Split(server, ",")
  475. if len(serverSettings) == 4 { //if line contains all 4 settings
  476. //ip, database, startID, endID
  477. //create SQL connection string //db, err := sql.Open("mysql", "remote_guest:d0gemuchw0w@tcp(192.168.1.xxx:3306)/wiby?charset=utf8mb4")
  478. serverIP := serverSettings[0]
  479. shard = serverSettings[1]
  480. startID := serverSettings[2]
  481. endID := serverSettings[3]
  482. sqlString := "remote_guest:d0gemuchw0w@tcp(" + serverIP + ":3306)/wiby?charset=utf8mb4"
  483. // fmt.Printf("%s %s %s %d\n",sqlString,startID,endID,numServers)
  484. //send special distributed query, only need ID returned
  485. if(shards==false){//depricated
  486. /*if(exactMatch==false && urlDetected==false && oneword==false){
  487. sqlQuery = "SELECT id FROM windex WHERE id BETWEEN " + startID + " AND " + endID + " AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) AND Match(title) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 19 WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 16 WHEN MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN Match(title) AGAINST('" + query + "' IN BOOLEAN MODE) THEN Match(title) AGAINST('" + query + "' IN BOOLEAN MODE) WHEN MATCH(body) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 1 WHEN MATCH(url) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 0 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
  488. }else{
  489. sqlQuery = "SELECT id FROM windex WHERE id BETWEEN " + startID + " AND " + endID + " AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 19 WHEN MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(url) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 0 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
  490. }*/
  491. }else{
  492. if(exactMatch==false && urlDetected==false && oneword==false && flagssetbyuser + wordcount != flagssetbyuser){
  493. sqlQuery = "SELECT id FROM " + shard + " WHERE MATCH(tags, body, description, title, url) AGAINST('" + reqwordQuery_filtered + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) OR MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(title) AGAINST('" + reqwordQuery_filtered + "' IN BOOLEAN MODE) THEN 14 WHEN MATCH(title) AGAINST('" + querytouse_filtered + "' IN BOOLEAN MODE) THEN 13 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
  494. }else{
  495. sqlQuery = "SELECT id FROM " + shard + " WHERE MATCH(tags, body, description, title, url) AGAINST('" + queryWithQuotesAndFlags_filtered + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags_filtered + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags_filtered + "' IN BOOLEAN MODE) THEN 20 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
  496. }
  497. }
  498. go distributedQuery(sqlString, sqlQuery, startID, endID, idListChans[serverCount])
  499. serverCount++
  500. }
  501. }
  502. for i := 0; i < serverCount; i++ {
  503. //wait for channels to complete and collect results
  504. idList += <-idListChans[i]
  505. }
  506. if len(idList) > 0 {
  507. switch strings.Contains(idList, "e") {
  508. case true:
  509. repsearchfail = 1
  510. default:
  511. idList = idList[1:len(idList)] //trim the first comma in the list
  512. }
  513. } else {
  514. noresults = 1
  515. }
  516. //fmt.Printf("\nChan: %s",idList)
  517. }
  518. //init the db and set charset
  519. //create SQL connection string
  520. db, err := sql.Open("mysql", "guest:qwer@/wiby?charset=utf8mb4")
  521. if err != nil {
  522. p := indexPage{}
  523. t, _ := template.ParseFiles("coreassets/error.html.go")
  524. t.Execute(w, p)
  525. }
  526. defer db.Close()
  527. // If Open doesn't open a connection. Validate DSN data:
  528. err = db.Ping()
  529. if err != nil {
  530. error.Error = err.Error()
  531. t, _ := template.ParseFiles("coreassets/error.html.go")
  532. t.Execute(w, error)
  533. }
  534. count := 0
  535. countResults := 0
  536. var ids[] string
  537. //if all went well with replication servers, send query to master containing idList and use the rangeOffset
  538. if numServers == serverCount && numServers > 0 && repsearchfail == 0 {
  539. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE id IN (" + idList + ") AND enable = '1' " + additions + "ORDER BY CASE WHEN LOCATE('" + queryNoQuotesOrFlags + "', tags) THEN 30 " + isURLlocate + " WHEN LOCATE('" + queryNoQuotesOrFlags + "', title) THEN 20 WHEN LOCATE('" + queryNoQuotesOrFlags + "', body) OR LOCATE('" + queryNoQuotesOrFlags + "', description) THEN 15" + partialLocate + " END DESC, id DESC LIMIT " + lim + " OFFSET " + strconv.Itoa(rangeOffset) + ""
  540. } else { //else, if no replication servers or there was some sort of error, just search the database locally instead
  541. if(exactMatch==false && urlDetected==false && oneword==false && flagssetbyuser + wordcount != flagssetbyuser){
  542. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE MATCH(tags, body, description, title, url) AGAINST('" + querytouse + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) OR MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(title) AGAINST('" + reqwordQuery + "' IN BOOLEAN MODE) THEN 14 WHEN MATCH(title) AGAINST('" + querytouse + "' IN BOOLEAN MODE) THEN 13 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
  543. }else{
  544. if(shards==false){//depricated
  545. /*sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 19 WHEN MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(url) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 0 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""*/
  546. }else{
  547. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE MATCH(tags, body, description, title, url) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
  548. }
  549. }
  550. }
  551. switch noresults { //if noresults == 1, no results were found during search on active replication servers
  552. case 0:
  553. // Send the query
  554. rows, err := db.Query(sqlQuery)
  555. if err != nil {
  556. fmt.Printf("\n%s", err)
  557. res.Page = strconv.Itoa(0)
  558. res.Query = m["q"][0] //get original unsafe query
  559. if json {
  560. w.Header().Set("Content-Type", "application/json")
  561. t, _ := template.ParseFiles("coreassets/json/results.json.go")
  562. t.Execute(w, res)
  563. } else {
  564. t, _ := template.ParseFiles("coreassets/results.html.go")
  565. t.Execute(w, res)
  566. }
  567. //p := indexPage{}
  568. //t, _ := template.ParseFiles("coreassets/form.html.go")
  569. //t.Execute(w, p)
  570. return
  571. }
  572. if urlDetected == true {
  573. query = queryOriginal
  574. }
  575. wordtocheck := ""
  576. stringtofind := strings.ToLower(queryNoQuotesOrFlags)
  577. stringtofind = strings.Replace(stringtofind, "''", "'", -1)
  578. requiredwordtofind := strings.ToLower(requiredword)
  579. requiredwordtofind = strings.Replace(requiredwordtofind, "''", "'", -1)
  580. longestWordtofind := strings.ToLower(longestWord)
  581. longestWordtofind = strings.Replace(longestWordtofind, "''", "'", -1)
  582. for rows.Next() {
  583. count++
  584. countResults++
  585. //this will get set if position of longest word of query is found within body
  586. pos := -1
  587. err := rows.Scan(&id, &url, &title, &description, &body)
  588. if err != nil {
  589. error.Error = err.Error()
  590. t, _ := template.ParseFiles("coreassets/error.html.go")
  591. t.Execute(w, error)
  592. }
  593. ids = append(ids,id)
  594. //find query inside body of page
  595. if exactMatch == false && (numRequiredWords == 0 || numRequiredWords + wordcount == numRequiredWords){
  596. if len(requiredword) > 0 { //search for position of required word if any, else search for position of whole query
  597. pos = strings.Index(strings.ToLower(body), requiredwordtofind)
  598. } else if pos == -1 {
  599. pos = strings.Index(strings.ToLower(body), stringtofind)
  600. }
  601. if pos == -1 { //not found? find position of longest query word
  602. pos = strings.Index(strings.ToLower(body), longestWordtofind)
  603. //not found?, set position to a different word
  604. if pos == -1 && wordcount > 1 {
  605. if longestwordelementnum > 0 {
  606. //wordtocheck = strings.Replace(words[0], "*", "", -1)
  607. wordtocheck = strings.Replace(words[0], "''", "'", -1)
  608. pos = strings.Index(strings.ToLower(body), strings.ToLower(wordtocheck))
  609. }
  610. if longestwordelementnum == 0 {
  611. //wordtocheck = strings.Replace(words[1], "*", "", -1)
  612. wordtocheck = strings.Replace(words[1], "''", "'", -1)
  613. pos = strings.Index(strings.ToLower(body), strings.ToLower(wordtocheck))
  614. }
  615. }
  616. }
  617. } else { //if exact match, find position of query within body
  618. pos = strings.Index(strings.ToLower(body), stringtofind)
  619. }
  620. //still not found?, set position to 0
  621. if pos == -1 {
  622. pos = 0
  623. }
  624. //Adjust position for runes within body
  625. pos = utf8.RuneCountInString(body[:pos])
  626. starttext := 0
  627. //ballpark := 0
  628. ballparktext := ""
  629. //figure out how much preceding text to use
  630. if pos < 32 {
  631. starttext = 0
  632. } else if pos > 25 {
  633. starttext = pos - 25
  634. } else if pos > 20 {
  635. starttext = pos - 15
  636. }
  637. //total length of the ballpark
  638. textlength := 180
  639. //populate the ballpark
  640. if pos >= 0 {
  641. ballparktext = substr(body, starttext, starttext+textlength)
  642. } //else{ ballpark = 0}//looks unused
  643. //find position of nearest Period
  644. //foundPeriod := true
  645. posPeriod := strings.Index(ballparktext, ". ") + starttext + 1
  646. //find position of nearest Space
  647. //foundSpace := true
  648. posSpace := strings.Index(ballparktext, " ") + starttext
  649. //if longest word in query is after a period+space within ballpark, reset starttext to that point
  650. if (pos - starttext) > posPeriod {
  651. starttext = posPeriod
  652. //populate the bodymatch
  653. if (pos - starttext) >= 0 {
  654. body = substr(body, starttext, starttext+textlength)
  655. } else {
  656. body = ""
  657. }
  658. } else if pos > posSpace { //else if longest word in query is after a space within ballpark, reset starttext to that point
  659. //else if(pos-starttext) > posSpace//else if longest word in query is after a space within ballpark, reset starttext to that point
  660. starttext = posSpace
  661. //populate the bodymatch
  662. if (pos - starttext) >= 0 {
  663. body = substr(body, starttext, starttext+textlength)
  664. } else {
  665. body = ""
  666. }
  667. } else //else just set the bodymatch to the ballparktext
  668. {
  669. //populate the bodymatch
  670. if (pos - starttext) >= 0 {
  671. body = ballparktext
  672. } else {
  673. body = ""
  674. }
  675. }
  676. tRes.Id = id
  677. tRes.Url = url
  678. tRes.Title = html.UnescapeString(title)
  679. tRes.Description = html.UnescapeString(description)
  680. tRes.Body = html.UnescapeString(body)
  681. if json == true {
  682. tRes.Title = JSONRealEscapeString(tRes.Title)
  683. tRes.Description = JSONRealEscapeString(tRes.Description)
  684. tRes.Body = JSONRealEscapeString(tRes.Body)
  685. }
  686. res.DBResults = append(res.DBResults, tRes)
  687. }
  688. defer rows.Close()
  689. rows.Close()
  690. if count > 0 { //new search method may cause less than the limit of row results per page even if there are more results to come, so we force a full count
  691. count = limInt
  692. }
  693. } //end switch
  694. //================================================================================================================================
  695. //no results found (count==0), so do a wildcard search (repeat the above process) - this section will probably be removed, no longer useful
  696. addWildcard := false
  697. /*if count == 0 && offset == "0" && urlDetected == false && exactMatch == false {
  698. addWildcard = true
  699. query = strings.Replace(query, "\"", "", -1) //remove some things innodb gets fussy over
  700. query = strings.Replace(query, "*", "", -1)
  701. query = strings.Replace(query, "'", "", -1)
  702. queryNoQuotes = strings.Replace(queryNoQuotes, "\"", "", -1)
  703. queryNoQuotes = strings.Replace(queryNoQuotes, "*", "", -1)
  704. queryNoQuotes = strings.Replace(queryNoQuotes, "'", "", -1)
  705. query = query + "*"
  706. if shards == false{
  707. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
  708. }else{
  709. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE Match(tags, body, description, title, url) Against('" + query + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
  710. }
  711. if repsearchfail == 0 && noservers == false {
  712. serverCount = 0
  713. idList = ""
  714. for _, server := range servers {
  715. serverSettings := strings.Split(server, ",")
  716. if len(serverSettings) == 4 { //if line contains all 4 settings
  717. //ip, database, startID, endID
  718. //create SQL connection string //db, err := sql.Open("mysql", "remote_guest:d0gemuchw0w@tcp(10.8.0.102:3306)/wiby?charset=utf8mb4")
  719. serverIP := serverSettings[0]
  720. shard := serverSettings[1]
  721. startID := serverSettings[2]
  722. endID := serverSettings[3]
  723. sqlString := "remote_guest:d0gemuchw0w@tcp(" + serverIP + ":3306)/wiby?charset=utf8mb4"
  724. //fmt.Printf("%s %s %s %d\n",sqlString,startID,endID,numServers)
  725. //send special distributed query, only need ID returned
  726. if(shards==false){//depricated
  727. sqlQuery = "SELECT id FROM windex WHERE id BETWEEN " + startID + " AND " + endID + " AND enable = '1' " + additions + " ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
  728. }else{
  729. sqlQuery = "SELECT id FROM " + shard + " WHERE Match(tags, body, description, title, url) Against('" + query + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
  730. }
  731. go distributedQuery(sqlString, sqlQuery, startID, endID, idListChans[serverCount])
  732. serverCount++
  733. }
  734. }
  735. for i := 0; i < serverCount; i++ {
  736. //wait for channels to complete and collect results
  737. idList += <-idListChans[i]
  738. }
  739. if len(idList) > 0 {
  740. switch strings.Contains(idList, "e") {
  741. case true:
  742. repsearchfail = 1
  743. default:
  744. idList = idList[1:len(idList)] //trim the first comma in the list
  745. }
  746. } else {
  747. noresults = 1
  748. }
  749. //if all went well with replication servers, send query to local database containing idList and use the rangeOffset
  750. if numServers == serverCount && numServers > 0 && repsearchfail == 0 {
  751. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE id IN (" + idList + ") AND enable = '1' " + additions + "ORDER BY CASE WHEN LOCATE('" + queryNoQuotes + "', tags) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + strconv.Itoa(rangeOffset) + ""
  752. } else { //else, if no replication servers or there was some sort of error, search the whole local database instead
  753. if shards == false{
  754. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
  755. }else{
  756. sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE Match(tags, body, description, title, url) Against('" + query + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
  757. }
  758. }
  759. }
  760. rows2, err := db.Query(sqlQuery)
  761. if err != nil {
  762. res.Page = strconv.Itoa(0)
  763. res.Query = m["q"][0] //get original unsafe query
  764. if json {
  765. w.Header().Set("Content-Type", "application/json")
  766. t, _ := template.ParseFiles("coreassets/json/results.json.go")
  767. t.Execute(w, res)
  768. } else {
  769. t, _ := template.ParseFiles("coreassets/results.html.go")
  770. t.Execute(w, res)
  771. }
  772. return
  773. }
  774. wordtocheck := ""
  775. stringtofind := strings.ToLower(queryNoQuotesOrFlags)
  776. stringtofind = strings.Replace(stringtofind, "''", "'", -1)
  777. requiredwordtofind := strings.ToLower(requiredword)
  778. requiredwordtofind = strings.Replace(requiredwordtofind, "''", "'", -1)
  779. longestWordtofind := strings.ToLower(longestWord)
  780. longestWordtofind = strings.Replace(longestWordtofind, "''", "'", -1)
  781. for rows2.Next() {
  782. count++
  783. //this will get set if position of longest word of query is found within body
  784. pos := -1
  785. err := rows2.Scan(&id, &url, &title, &description, &body)
  786. if err != nil {
  787. error.Error = err.Error()
  788. t, _ := template.ParseFiles("coreassets/error.html.go")
  789. t.Execute(w, error)
  790. }
  791. //find query inside body of page
  792. if exactMatch == false && (numRequiredWords == 0 || numRequiredWords + wordcount == numRequiredWords){
  793. if len(requiredword) > 0 { //search for position of required word if any, else search for position of whole query
  794. pos = strings.Index(strings.ToLower(body), requiredwordtofind)
  795. } else if pos == -1 {
  796. pos = strings.Index(strings.ToLower(body), stringtofind)
  797. }
  798. if pos == -1 { //not found? find position of longest query word
  799. pos = strings.Index(strings.ToLower(body), longestWordtofind)
  800. //not found?, set position to a different word
  801. if pos == -1 && wordcount > 1 {
  802. if longestwordelementnum > 0 {
  803. //wordtocheck = strings.Replace(words[0], "*", "", -1)
  804. wordtocheck = strings.Replace(words[0], "''", "'", -1)
  805. pos = strings.Index(strings.ToLower(body), strings.ToLower(wordtocheck))
  806. }
  807. if longestwordelementnum == 0 {
  808. //wordtocheck = strings.Replace(words[1], "*", "", -1)
  809. wordtocheck = strings.Replace(words[1], "''", "'", -1)
  810. pos = strings.Index(strings.ToLower(body), strings.ToLower(wordtocheck))
  811. }
  812. }
  813. }
  814. } else { //if exact match, find position of query within body
  815. pos = strings.Index(strings.ToLower(body), stringtofind)
  816. }
  817. //still not found?, set position to 0
  818. if pos == -1 {
  819. pos = 0
  820. }
  821. //Adjust position for runes within body
  822. pos = utf8.RuneCountInString(body[:pos])
  823. starttext := 0
  824. //ballpark := 0
  825. ballparktext := ""
  826. //figure out how much preceding text to use
  827. if pos < 32 {
  828. starttext = 0
  829. } else if pos > 25 {
  830. starttext = pos - 25
  831. } else if pos > 20 {
  832. starttext = pos - 15
  833. }
  834. //total length of the ballpark
  835. textlength := 180
  836. //populate the ballpark
  837. if pos >= 0 {
  838. ballparktext = substr(body, starttext, starttext+textlength)
  839. } //else{ ballpark = 0}//looks unused
  840. //find position of nearest Period
  841. //foundPeriod := true
  842. posPeriod := strings.Index(ballparktext, ". ") + starttext + 1
  843. //find position of nearest Space
  844. //foundSpace := true
  845. posSpace := strings.Index(ballparktext, " ") + starttext
  846. //if longest word in query is after a period+space within ballpark, reset starttext to that point
  847. if (pos - starttext) > posPeriod {
  848. starttext = posPeriod
  849. //populate the bodymatch
  850. if (pos - starttext) >= 0 {
  851. body = substr(body, starttext, starttext+textlength)
  852. } else {
  853. body = ""
  854. }
  855. } else if pos > posSpace { //else if longest word in query is after a space within ballpark, reset starttext to that point
  856. //else if(pos-starttext) > posSpace//else if longest word in query is after a space within ballpark, reset starttext to that point
  857. starttext = posSpace
  858. //populate the bodymatch
  859. if (pos - starttext) >= 0 {
  860. body = substr(body, starttext, starttext+textlength)
  861. } else {
  862. body = ""
  863. }
  864. } else //else just set the bodymatch to the ballparktext
  865. {
  866. //populate the bodymatch
  867. if (pos - starttext) >= 0 {
  868. body = ballparktext
  869. } else {
  870. body = ""
  871. }
  872. }
  873. tRes.Id = id
  874. tRes.Url = url
  875. tRes.Title = html.UnescapeString(title)
  876. tRes.Description = html.UnescapeString(description)
  877. tRes.Body = html.UnescapeString(body)
  878. if json == true {
  879. tRes.Title = JSONRealEscapeString(tRes.Title)
  880. tRes.Description = JSONRealEscapeString(tRes.Description)
  881. tRes.Body = JSONRealEscapeString(tRes.Body)
  882. }
  883. res.DBResults = append(res.DBResults, tRes)
  884. }
  885. defer rows2.Close()
  886. rows2.Close()
  887. }*/
  888. //=======================================================================================================================
  889. //http://go-database-sql.org/retrieving.html
  890. //Close DB
  891. db.Close()
  892. //allow the find more link
  893. if (countResults >= limInt || countResults > 2) && addWildcard == false{
  894. res.FindMore = true
  895. } else {
  896. res.FindMore = false
  897. }
  898. if(pageInt == 0){
  899. pageInt+=2
  900. }else{
  901. pageInt++;
  902. }
  903. res.Page = strconv.Itoa(pageInt)
  904. res.Query = m["q"][0] //get original unsafe query
  905. if json {
  906. w.Header().Set("Content-Type", "application/json")
  907. t, _ := template.ParseFiles("coreassets/json/results.json.go")
  908. t.Execute(w, res)
  909. } else {
  910. t, _ := template.ParseFiles("coreassets/results.html.go")
  911. t.Execute(w, res)
  912. }
  913. }
  914. }
  915. func settings(w http.ResponseWriter, r *http.Request) {
  916. //setup for error report
  917. error := errorReport{}
  918. //check if worksafe (adult content) cookie enabled.
  919. filterHTTPS := false
  920. worksafe := true
  921. worksafewasoff := false
  922. worksafeHTTPSCookie, err := r.Cookie("ws")
  923. if err != nil {
  924. worksafe = true
  925. filterHTTPS = false
  926. } else if worksafeHTTPSCookie.Value == "0" {
  927. worksafe = false
  928. filterHTTPS = false
  929. worksafewasoff = true
  930. } else if worksafeHTTPSCookie.Value == "1" {
  931. worksafe = true
  932. filterHTTPS = false
  933. } else if worksafeHTTPSCookie.Value == "2" {
  934. worksafe = false
  935. filterHTTPS = true
  936. worksafewasoff = true
  937. } else if worksafeHTTPSCookie.Value == "3" {
  938. worksafe = true
  939. filterHTTPS = true
  940. }
  941. //check if and what is the user posting
  942. switch r.Method {
  943. case "POST":
  944. if err := r.ParseForm(); err != nil {
  945. error.Error = err.Error()
  946. t, _ := template.ParseFiles("coreassets/error.html.go")
  947. t.Execute(w, error)
  948. }
  949. worksafebox := r.Form.Get("worksafe")
  950. agreecheck := r.Form.Get("agree")
  951. agreesubmit := r.Form.Get("agreesubmit")
  952. httpsbox := r.Form.Get("filterHTTPS")
  953. //if user agrees to terms to disable adult content, set cookie and return to index
  954. if agreecheck == "on" {
  955. worksafe = false
  956. //expiration := time.Now().Add(365 * 24 * time.Hour)
  957. if filterHTTPS == false {
  958. cookie := http.Cookie{Name: "ws", Value: "0", Path: "/"}
  959. http.SetCookie(w, &cookie)
  960. } else {
  961. cookie := http.Cookie{Name: "ws", Value: "2", Path: "/"}
  962. http.SetCookie(w, &cookie)
  963. }
  964. p := indexPage{}
  965. t, _ := template.ParseFiles("coreassets/settings/gohome.html")
  966. t.Execute(w, p)
  967. //else if worksafebox is checked, return to index with worksafe on
  968. } else if worksafebox == "on" || agreesubmit == "on" {
  969. //expiration := time.Now().Add(365 * 24 * time.Hour)
  970. if httpsbox != "on" {
  971. cookie := http.Cookie{Name: "ws", Value: "1", Path: "/"}
  972. http.SetCookie(w, &cookie)
  973. } else {
  974. cookie := http.Cookie{Name: "ws", Value: "3", Path: "/"}
  975. http.SetCookie(w, &cookie)
  976. }
  977. p := indexPage{}
  978. t, _ := template.ParseFiles("coreassets/settings/gohome.html")
  979. t.Execute(w, p)
  980. //else if worksafebox unchecked and no cookie, go to content agreement section
  981. } else if worksafebox != "on" && worksafewasoff == false && agreesubmit != "on" {
  982. p := indexPage{}
  983. if httpsbox == "on" {
  984. cookie := http.Cookie{Name: "ws", Value: "3", Path: "/"}
  985. http.SetCookie(w, &cookie)
  986. } else {
  987. cookie := http.Cookie{Name: "ws", Value: "1", Path: "/"}
  988. http.SetCookie(w, &cookie)
  989. }
  990. t, _ := template.ParseFiles("coreassets/settings/agree.html.go")
  991. t.Execute(w, p)
  992. //else if worksafebox unchecked and cookie alredy agreed, go back to index
  993. } else if worksafebox != "on" && worksafewasoff == true {
  994. if httpsbox == "on" {
  995. cookie := http.Cookie{Name: "ws", Value: "2", Path: "/"}
  996. http.SetCookie(w, &cookie)
  997. } else {
  998. cookie := http.Cookie{Name: "ws", Value: "0", Path: "/"}
  999. http.SetCookie(w, &cookie)
  1000. }
  1001. p := indexPage{}
  1002. t, _ := template.ParseFiles("coreassets/settings/gohome.html")
  1003. t.Execute(w, p)
  1004. }
  1005. default:
  1006. //load the settings page if no post value
  1007. settingspage := settingsPage{}
  1008. settingspage.Worksafe = worksafe
  1009. settingspage.FilterHTTPS = filterHTTPS
  1010. t, _ := template.ParseFiles("coreassets/settings/settings.html.go")
  1011. t.Execute(w, settingspage)
  1012. }
  1013. }
  1014. func surprise(w http.ResponseWriter, r *http.Request) {
  1015. surprise := surpriseURL{}
  1016. //check if worksafe+HTTPS cookie enabled.
  1017. filterHTTPS := false
  1018. worksafeHTTPSCookie, err := r.Cookie("ws")
  1019. if err != nil {
  1020. filterHTTPS = false
  1021. } else if worksafeHTTPSCookie.Value == "2" {
  1022. filterHTTPS = true
  1023. } else if worksafeHTTPSCookie.Value == "3" {
  1024. filterHTTPS = true
  1025. }
  1026. //setup for error report
  1027. error := errorReport{}
  1028. //init the db and set charset
  1029. db, err := sql.Open("mysql", "guest:qwer@/wiby?charset=utf8mb4")
  1030. if err != nil {
  1031. error.Error = err.Error()
  1032. t, _ := template.ParseFiles("coreassets/error.html.go")
  1033. t.Execute(w, error)
  1034. }
  1035. defer db.Close()
  1036. // Open doesn't open a connection. Validate DSN data:
  1037. err = db.Ping()
  1038. if err != nil {
  1039. error.Error = err.Error()
  1040. t, _ := template.ParseFiles("coreassets/error.html.go")
  1041. t.Execute(w, error)
  1042. }
  1043. //grab a random page
  1044. var sqlQuery string
  1045. if filterHTTPS == false {
  1046. sqlQuery = "select url from windex where worksafe = 1 and surprise = 1 order by rand() limit 1"
  1047. } else {
  1048. sqlQuery = "select url from windex where worksafe = 1 and surprise = 1 and http = 1 order by rand() limit 1"
  1049. }
  1050. rows, err := db.Query(sqlQuery)
  1051. if err != nil {
  1052. error.Error = err.Error()
  1053. t, _ := template.ParseFiles("coreassets/error.html.go")
  1054. t.Execute(w, error)
  1055. }
  1056. var url string
  1057. for rows.Next() {
  1058. err := rows.Scan(&url)
  1059. if err != nil {
  1060. error.Error = err.Error()
  1061. t, _ := template.ParseFiles("coreassets/error.html.go")
  1062. t.Execute(w, error)
  1063. }
  1064. surprise.Url = url
  1065. }
  1066. defer rows.Close()
  1067. rows.Close()
  1068. db.Close()
  1069. t, _ := template.ParseFiles("coreassets/surprise.html.go")
  1070. t.Execute(w, surprise)
  1071. }
  1072. func MysqlRealEscapeString(value string) string {
  1073. replace := map[string]string{"\\": "\\\\", "'": `\'`, "\\0": "\\\\0", "\n": "\\n", "\r": "\\r", `"`: `\"`, "\x1a": "\\Z"}
  1074. for b, a := range replace {
  1075. value = strings.Replace(value, b, a, -1)
  1076. }
  1077. return value
  1078. }
  1079. func JSONRealEscapeString(value string) string {
  1080. replace := map[string]string{"\\": "\\\\", "\t": "\\t", "\b": "\\b", "\n": "\\n", "\r": "\\r", "\f": "\\f" /*, `"`:`\"`*/}
  1081. for b, a := range replace {
  1082. value = strings.Replace(value, b, a, -1)
  1083. }
  1084. //remove control characters
  1085. buf := []rune(value)
  1086. for i, v := range buf {
  1087. if v < 32 || v == 127 {
  1088. buf[i]=32
  1089. }
  1090. }
  1091. return string(buf)
  1092. }
  1093. func substr(s string, start int, end int) string {
  1094. start_str_idx := 0
  1095. i := 0
  1096. for j := range s {
  1097. if i == start {
  1098. start_str_idx = j
  1099. }
  1100. if i == end {
  1101. return s[start_str_idx:j]
  1102. }
  1103. i++
  1104. }
  1105. return s[start_str_idx:]
  1106. }
  1107. func searchredirect(w http.ResponseWriter, r *http.Request, query string) {
  1108. //separate actual query from search redirect
  1109. actualquery := ""
  1110. redirect := ""
  1111. lenquery := len(query)
  1112. if strings.Index(query," ") > -1{
  1113. location := strings.Index(query, " !")
  1114. if location == -1 {
  1115. location = strings.Index(query, " &")
  1116. }
  1117. if location > -1 && strings.Index(query[location+1:lenquery], " ") == -1 { //redirect is at end of query
  1118. redirect = query[location+2 : lenquery]
  1119. actualquery = query[:location]
  1120. } else if (strings.Index(query, "!") == 0 || strings.Index(query, "&") == 0){ //redirect is at start of query
  1121. redirect = query[1:strings.Index(query, " ")]
  1122. actualquery = query[strings.Index(query, " ")+1:]
  1123. //fmt.Printf("\nRedirect: %s\nquery: %s\n",redirect,actualquery)
  1124. }
  1125. redirect = strings.ToLower(redirect)
  1126. }else if (query[0] == '!' || query[0] == '&') && lenquery > 1{
  1127. redirect = query[1:]
  1128. }
  1129. if redirect != "" {
  1130. //determine which search engine to redirect
  1131. if redirect == "g" { //if google text search
  1132. http.Redirect(w, r, "http://google.com/search?q="+actualquery, http.StatusSeeOther)
  1133. } else if redirect == "b" { //if bing text search
  1134. http.Redirect(w, r, "http://bing.com/search?q="+actualquery, http.StatusSeeOther)
  1135. } else if redirect == "gi" { //if google image search
  1136. http.Redirect(w, r, "http://www.google.com/search?tbm=isch&q="+actualquery, http.StatusSeeOther)
  1137. } else if redirect == "bi" { //if bing image search
  1138. http.Redirect(w, r, "http://www.bing.com/images/search?q="+actualquery, http.StatusSeeOther)
  1139. } else if redirect == "gv" { //if google video search
  1140. http.Redirect(w, r, "http://www.google.com/search?tbm=vid&q="+actualquery, http.StatusSeeOther)
  1141. } else if redirect == "bv" { //if bing video search
  1142. http.Redirect(w, r, "http://www.bing.com/videos/search?q="+actualquery, http.StatusSeeOther)
  1143. } else if redirect == "gm" { //if google maps search
  1144. http.Redirect(w, r, "http://www.google.com/maps/search/"+actualquery, http.StatusSeeOther)
  1145. } else if redirect == "bm" { //if bing maps search
  1146. http.Redirect(w, r, "http://www.bing.com/maps?q="+actualquery, http.StatusSeeOther)
  1147. }/* else {
  1148. http.Redirect(w, r, "/?q="+actualquery, http.StatusSeeOther)
  1149. }*/
  1150. }
  1151. }
  1152. func distributedQuery(con string, sqlQuery string, startID string, endID string, idListChan chan<- string) {
  1153. var id string
  1154. var idList string
  1155. count := 0
  1156. //defer wg.Done()
  1157. //init the db
  1158. db, err := sql.Open("mysql", con)
  1159. if err != nil {
  1160. idList = idList + "e" //will look for this when channels are processed
  1161. }
  1162. defer db.Close()
  1163. // If Open doesn't open a connection. Validate DSN data:
  1164. err = db.Ping()
  1165. if err != nil {
  1166. }
  1167. //fmt.Printf("%s\n", sqlQuery)
  1168. // Send the query
  1169. rows, err := db.Query(sqlQuery)
  1170. if err == nil {
  1171. for rows.Next() {
  1172. err := rows.Scan(&id)
  1173. if err != nil {
  1174. }
  1175. //idString = idstring + "id = " + id + " or "
  1176. idList += "," + id
  1177. count++
  1178. }
  1179. } else {
  1180. idList = idList + "e" //will look for this when channels are processed
  1181. fmt.Printf("%s", err)
  1182. }
  1183. //fmt.Printf("%s - %s\n", idList,con)
  1184. idListChan <- idList
  1185. }