alamin655 commited on
Commit
388aaf4
·
unverified ·
2 Parent(s): efa8efc 31c9c67

Merge pull request #470 from ddotthomas/FIX/463_results_from_different_search_engines_get_cached_as_the_same_key

Browse files
src/models/server_models.rs CHANGED
@@ -1,7 +1,11 @@
1
  //! This module provides the models to parse cookies and search parameters from the search
2
  //! engine website.
 
 
3
  use serde::Deserialize;
4
 
 
 
5
  /// A named struct which deserializes all the user provided search parameters and stores them.
6
  #[derive(Deserialize)]
7
  pub struct SearchParams {
@@ -21,11 +25,24 @@ pub struct SearchParams {
21
  #[derive(Deserialize)]
22
  pub struct Cookie<'a> {
23
  /// It stores the theme name used in the website.
24
- pub theme: &'a str,
25
  /// It stores the colorscheme name used for the website theme.
26
- pub colorscheme: &'a str,
27
  /// It stores the user selected upstream search engines selected from the UI.
28
- pub engines: Vec<&'a str>,
29
  /// It stores the user selected safe search level from the UI.
30
  pub safe_search_level: u8,
31
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  //! This module provides the models to parse cookies and search parameters from the search
2
  //! engine website.
3
+ use std::borrow::Cow;
4
+
5
  use serde::Deserialize;
6
 
7
+ use super::parser_models::Style;
8
+
9
  /// A named struct which deserializes all the user provided search parameters and stores them.
10
  #[derive(Deserialize)]
11
  pub struct SearchParams {
 
25
  #[derive(Deserialize)]
26
  pub struct Cookie<'a> {
27
  /// It stores the theme name used in the website.
28
+ pub theme: Cow<'a, str>,
29
  /// It stores the colorscheme name used for the website theme.
30
+ pub colorscheme: Cow<'a, str>,
31
  /// It stores the user selected upstream search engines selected from the UI.
32
+ pub engines: Cow<'a, Vec<Cow<'a, str>>>,
33
  /// It stores the user selected safe search level from the UI.
34
  pub safe_search_level: u8,
35
  }
36
+
37
+ impl<'a> Cookie<'a> {
38
+ /// server_models::Cookie contructor function
39
+ pub fn build(style: &'a Style, mut engines: Vec<Cow<'a, str>>, safe_search_level: u8) -> Self {
40
+ engines.sort();
41
+ Self {
42
+ theme: Cow::Borrowed(&style.theme),
43
+ colorscheme: Cow::Borrowed(&style.colorscheme),
44
+ engines: Cow::Owned(engines),
45
+ safe_search_level,
46
+ }
47
+ }
48
+ }
src/server/routes/search.rs CHANGED
@@ -6,14 +6,15 @@ use crate::{
6
  handler::{file_path, FileType},
7
  models::{
8
  aggregation_models::SearchResults,
9
- engine_models::{EngineError, EngineHandler},
10
- server_models::{Cookie, SearchParams},
11
  },
12
  results::aggregator::aggregate,
13
  };
14
  use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
15
  use regex::Regex;
16
  use std::{
 
17
  fs::File,
18
  io::{BufRead, BufReader, Read},
19
  };
@@ -48,16 +49,33 @@ pub async fn search(
48
  .finish());
49
  }
50
 
51
- let get_results = |page| {
52
- results(
53
- &config,
54
- &cache,
55
- query,
56
- page,
57
- req.clone(),
58
- &params.safesearch,
59
- )
60
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  // .max(1) makes sure that the page >= 0.
63
  let page = params.page.unwrap_or(1).max(1) - 1;
@@ -105,25 +123,19 @@ async fn results(
105
  cache: &web::Data<SharedCache>,
106
  query: &str,
107
  page: u32,
108
- req: HttpRequest,
109
- safe_search: &Option<u8>,
110
  ) -> Result<SearchResults, Box<dyn std::error::Error>> {
111
  // eagerly parse cookie value to evaluate safe search level
112
- let cookie_value = req.cookie("appCookie");
113
-
114
- let cookie_value: Option<Cookie<'_>> = cookie_value
115
- .as_ref()
116
- .and_then(|cv| serde_json::from_str(cv.name_value().1).ok());
117
-
118
- let safe_search_level = get_safesearch_level(
119
- safe_search,
120
- &cookie_value.as_ref().map(|cv| cv.safe_search_level),
121
- config.safe_search,
122
- );
123
 
124
  let cache_key = format!(
125
- "http://{}:{}/search?q={}&page={}&safesearch={}",
126
- config.binding_ip, config.port, query, page, safe_search_level
 
 
 
 
 
127
  );
128
 
129
  // fetch the cached results json.
@@ -151,51 +163,28 @@ async fn results(
151
  // default selected upstream search engines from the config file otherwise
152
  // parse the non-empty cookie and grab the user selected engines from the
153
  // UI and use that.
154
- let mut results: SearchResults = match cookie_value {
155
- Some(cookie_value) => {
156
- let engines: Vec<EngineHandler> = cookie_value
157
- .engines
158
- .iter()
159
- .filter_map(|name| EngineHandler::new(name).ok())
160
- .collect();
161
-
162
- match engines.is_empty() {
163
- false => {
164
- aggregate(
165
- query,
166
- page,
167
- config.aggregator.random_delay,
168
- config.debug,
169
- &engines,
170
- config.request_timeout,
171
- safe_search_level,
172
- )
173
- .await?
174
- }
175
- true => {
176
- let mut search_results = SearchResults::default();
177
- search_results.set_no_engines_selected();
178
- search_results
179
- }
180
- }
181
  }
182
- None => aggregate(
183
- query,
184
- page,
185
- config.aggregator.random_delay,
186
- config.debug,
187
- &config
188
- .upstream_search_engines
189
- .clone()
190
- .into_iter()
191
- .filter_map(|(key, value)| value.then_some(key))
192
- .map(|engine| EngineHandler::new(&engine))
193
- .collect::<Result<Vec<EngineHandler>, error_stack::Report<EngineError>>>(
194
- )?,
195
- config.request_timeout,
196
- safe_search_level,
197
- )
198
- .await?,
199
  };
200
  if results.engine_errors_info().is_empty()
201
  && results.results().is_empty()
@@ -237,23 +226,24 @@ fn is_match_from_filter_list(
237
  Ok(false)
238
  }
239
 
240
- /// A helper function which returns the safe search level based on the url params
241
- /// and cookie value.
 
242
  ///
243
  /// # Argurments
244
  ///
245
- /// * `safe_search` - Safe search level from the url.
246
- /// * `cookie` - User's cookie
247
- /// * `default` - Safe search level to fall back to
248
- fn get_safesearch_level(safe_search: &Option<u8>, cookie: &Option<u8>, default: u8) -> u8 {
249
- match safe_search {
250
- Some(ss) => {
251
- if *ss >= 3 {
252
- default
253
  } else {
254
- *ss
255
  }
256
  }
257
- None => cookie.unwrap_or(default),
258
  }
259
  }
 
6
  handler::{file_path, FileType},
7
  models::{
8
  aggregation_models::SearchResults,
9
+ engine_models::EngineHandler,
10
+ server_models::{self, SearchParams},
11
  },
12
  results::aggregator::aggregate,
13
  };
14
  use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
15
  use regex::Regex;
16
  use std::{
17
+ borrow::Cow,
18
  fs::File,
19
  io::{BufRead, BufReader, Read},
20
  };
 
49
  .finish());
50
  }
51
 
52
+ let cookie = req.cookie("appCookie");
53
+
54
+ // Get search settings using the user's cookie or from the server's config
55
+ let mut search_settings: server_models::Cookie<'_> = cookie
56
+ .and_then(|cookie_value| serde_json::from_str(cookie_value.value()).ok())
57
+ .unwrap_or_else(|| {
58
+ server_models::Cookie::build(
59
+ &config.style,
60
+ config
61
+ .upstream_search_engines
62
+ .iter()
63
+ .filter_map(|(engine, enabled)| {
64
+ enabled.then_some(Cow::Borrowed(engine.as_str()))
65
+ })
66
+ .collect(),
67
+ config.safe_search,
68
+ )
69
+ });
70
+
71
+ search_settings.safe_search_level = get_safesearch_level(
72
+ &Some(search_settings.safe_search_level),
73
+ &params.safesearch,
74
+ config.safe_search,
75
+ );
76
+
77
+ // Closure wrapping the results function capturing local references
78
+ let get_results = |page| results(&config, &cache, query, page, &search_settings);
79
 
80
  // .max(1) makes sure that the page >= 0.
81
  let page = params.page.unwrap_or(1).max(1) - 1;
 
123
  cache: &web::Data<SharedCache>,
124
  query: &str,
125
  page: u32,
126
+ search_settings: &server_models::Cookie<'_>,
 
127
  ) -> Result<SearchResults, Box<dyn std::error::Error>> {
128
  // eagerly parse cookie value to evaluate safe search level
129
+ let safe_search_level = search_settings.safe_search_level;
 
 
 
 
 
 
 
 
 
 
130
 
131
  let cache_key = format!(
132
+ "http://{}:{}/search?q={}&page={}&safesearch={}&engines={}",
133
+ config.binding_ip,
134
+ config.port,
135
+ query,
136
+ page,
137
+ safe_search_level,
138
+ search_settings.engines.join(",")
139
  );
140
 
141
  // fetch the cached results json.
 
163
  // default selected upstream search engines from the config file otherwise
164
  // parse the non-empty cookie and grab the user selected engines from the
165
  // UI and use that.
166
+ let mut results: SearchResults = match search_settings.engines.is_empty() {
167
+ false => {
168
+ aggregate(
169
+ query,
170
+ page,
171
+ config.aggregator.random_delay,
172
+ config.debug,
173
+ &search_settings
174
+ .engines
175
+ .iter()
176
+ .filter_map(|engine| EngineHandler::new(&engine).ok())
177
+ .collect::<Vec<EngineHandler>>(),
178
+ config.request_timeout,
179
+ safe_search_level,
180
+ )
181
+ .await?
182
+ }
183
+ true => {
184
+ let mut search_results = SearchResults::default();
185
+ search_results.set_no_engines_selected();
186
+ search_results
 
 
 
 
 
 
187
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  };
189
  if results.engine_errors_info().is_empty()
190
  && results.results().is_empty()
 
226
  Ok(false)
227
  }
228
 
229
+ /// A helper function to modify the safe search level based on the url params.
230
+ /// The `safe_search` is the one in the user's cookie or
231
+ /// the default set by the server config if the cookie was missing.
232
  ///
233
  /// # Argurments
234
  ///
235
+ /// * `url_level` - Safe search level from the url.
236
+ /// * `safe_search` - User's cookie, or the safe search level set by the server
237
+ /// * `config_level` - Safe search level to fall back to
238
+ fn get_safesearch_level(cookie_level: &Option<u8>, url_level: &Option<u8>, config_level: u8) -> u8 {
239
+ match url_level {
240
+ Some(url_level) => {
241
+ if *url_level >= 3 {
242
+ config_level
243
  } else {
244
+ *url_level
245
  }
246
  }
247
+ None => cookie_level.unwrap_or(config_level),
248
  }
249
  }