From 44a5070bf54da2e1f90e096833b5519806c1c31f Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 13 Jan 2015 23:18:28 -0300 Subject: added pyperclip dependency --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 953df2bb..f9c8d15e 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,8 @@ deps = { "pyasn1>0.1.2", "pyOpenSSL>=0.14", "tornado>=4.0.2", - "configargparse>=0.9.3" + "configargparse>=0.9.3", + "pyperclip>=1.5.7" } script_deps = { "mitmproxy": { -- cgit v1.2.3 From 34d355a62b3103e322793e2af652ee0aa867ddaf Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 10:52:52 -0300 Subject: wip - content copy is working, header representation is not --- libmproxy/console/flowlist.py | 16 ++++++++++++++++ libmproxy/protocol/http.py | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index c896ba33..89dc56a9 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import urwid +import pyperclip from . import common def _mkhelp(): @@ -136,6 +137,11 @@ class ConnectionItem(common.WWrap): self.state.last_saveload, self.master.server_playback_path ) + def server_copy_response(self, k): + if k == "c": + pyperclip.copy(self.flow.response_content()) + elif k == "t": + pyperclip.copy(self.flow.response_headers()) def keypress(self, (maxcol,), key): key = common.shortcuts(key) @@ -202,6 +208,16 @@ class ConnectionItem(common.WWrap): self.master.run_script_once, self.flow ) + elif key == "g": + #copy flow part + self.master.prompt_onekey( + "Copy Response", + ( + ("content", "c"), + ("headers", "h"), + ), + self.server_copy_response, + ) else: return key diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index da7c4240..4de1c0a6 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -953,6 +953,21 @@ class HTTPFlow(Flow): c += self.response.replace(pattern, repl, *args, **kwargs) return c + def response_content(self): + s = "[No Content]" + with decoded(self.response): + s = self.response.content + return s + + def response_headers(self): + with decoded(self.response): + sh = "" + for i in self.flow.response.headers: + v = self.flow.response.headers[i] + for j in v: + sh += str(i)+"="+str(v[j])+"\n" + return sh + class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): -- cgit v1.2.3 From a4bfa677e95b058c50d49b4b3ae986351ed0cbf8 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 12:03:40 -0300 Subject: now content and header are working and exception for binary files are handled correctly --- libmproxy/console/flowlist.py | 13 ++++++++++--- libmproxy/protocol/http.py | 14 ++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 89dc56a9..655df74d 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -13,6 +13,7 @@ def _mkhelp(): ("D", "duplicate flow"), ("e", "toggle eventlog"), ("F", "toggle follow flow list"), + ("g", "copy response(content/headers) to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -139,9 +140,15 @@ class ConnectionItem(common.WWrap): ) def server_copy_response(self, k): if k == "c": - pyperclip.copy(self.flow.response_content()) - elif k == "t": - pyperclip.copy(self.flow.response_headers()) + try: + pyperclip.copy(self.flow.response_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(self.flow.response_headers()) + except TypeError: + self.master.statusbar.message("Error converting headers to text") def keypress(self, (maxcol,), key): key = common.shortcuts(key) diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 4de1c0a6..f822fcc8 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -954,20 +954,18 @@ class HTTPFlow(Flow): return c def response_content(self): - s = "[No Content]" with decoded(self.response): s = self.response.content + if s == None: + s = "[No content]" return s def response_headers(self): with decoded(self.response): - sh = "" - for i in self.flow.response.headers: - v = self.flow.response.headers[i] - for j in v: - sh += str(i)+"="+str(v[j])+"\n" - return sh - + s = str(self.response.headers) + if s == None: + s = "[]" + return s class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): -- cgit v1.2.3 From 36ec20bbb8a0b91a265849c48a660b3fd29d7122 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 12:09:14 -0300 Subject: removed invalid comment and unneeded safe text --- libmproxy/console/flowlist.py | 1 - libmproxy/protocol/http.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 655df74d..d48f75a4 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -216,7 +216,6 @@ class ConnectionItem(common.WWrap): self.flow ) elif key == "g": - #copy flow part self.master.prompt_onekey( "Copy Response", ( diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index f822fcc8..9846fc5b 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -956,15 +956,11 @@ class HTTPFlow(Flow): def response_content(self): with decoded(self.response): s = self.response.content - if s == None: - s = "[No content]" return s def response_headers(self): with decoded(self.response): s = str(self.response.headers) - if s == None: - s = "[]" return s class HttpAuthenticationError(Exception): -- cgit v1.2.3 From d49eafad8b51bab837dc74d140aa04ed8c477cbc Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 12:36:19 -0300 Subject: added copy functionality to flowview too --- libmproxy/console/flowview.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 9e305b8a..25b085c3 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -4,7 +4,7 @@ import urwid from . import common, grideditor, contentview from .. import utils, flow, controller from ..protocol.http import HTTPResponse, CONTENT_MISSING, decoded - +import pyperclip class SearchError(Exception): pass @@ -19,6 +19,7 @@ def _mkhelp(): ("D", "duplicate flow"), ("e", "edit request/response"), ("f", "load full body data"), + ("g", "copy response(content/headers) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + @@ -648,6 +649,18 @@ class FlowView(common.WWrap): ) self.master.refresh_flow(self.flow) + def server_copy_response(self, k): + if k == "c": + try: + pyperclip.copy(self.flow.response_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(self.flow.response_headers()) + except TypeError: + self.master.statusbar.message("Error converting headers to text") + def delete_body(self, t): if t == "m": val = CONTENT_MISSING @@ -751,6 +764,15 @@ class FlowView(common.WWrap): ) self.master.refresh_flow(self.flow) self.master.statusbar.message("") + elif key == "g": + self.master.prompt_onekey( + "Copy Response", + ( + ("content", "c"), + ("headers", "h"), + ), + self.server_copy_response, + ) elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) -- cgit v1.2.3 From 6b8fb147d07d75aa81b0d5b5861c3cbbaeec7fbb Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 14:45:19 -0300 Subject: used get_decoded_content and removed decode call from headers as max suggested --- libmproxy/console/flowlist.py | 4 ++-- libmproxy/console/flowview.py | 4 ++-- libmproxy/protocol/http.py | 10 ---------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index d48f75a4..236bd508 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -141,12 +141,12 @@ class ConnectionItem(common.WWrap): def server_copy_response(self, k): if k == "c": try: - pyperclip.copy(self.flow.response_content()) + pyperclip.copy(self.flow.response.get_decoded_content()) except TypeError: self.master.statusbar.message("Content is binary or can be converted to text") elif k == "h": try: - pyperclip.copy(self.flow.response_headers()) + pyperclip.copy(str(self.flow.response.headers)) except TypeError: self.master.statusbar.message("Error converting headers to text") diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 25b085c3..08a0148f 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -652,12 +652,12 @@ class FlowView(common.WWrap): def server_copy_response(self, k): if k == "c": try: - pyperclip.copy(self.flow.response_content()) + pyperclip.copy(self.flow.response.get_decoded_content()) except TypeError: self.master.statusbar.message("Content is binary or can be converted to text") elif k == "h": try: - pyperclip.copy(self.flow.response_headers()) + pyperclip.copy(str(self.flow.response.headers)) except TypeError: self.master.statusbar.message("Error converting headers to text") diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 9846fc5b..50691ea2 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -953,16 +953,6 @@ class HTTPFlow(Flow): c += self.response.replace(pattern, repl, *args, **kwargs) return c - def response_content(self): - with decoded(self.response): - s = self.response.content - return s - - def response_headers(self): - with decoded(self.response): - s = str(self.response.headers) - return s - class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): super(HttpAuthenticationError, self).__init__( -- cgit v1.2.3 From 95f0b4b506230ee43ea7a6d736ab752400747bbb Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 16:44:59 -0300 Subject: trying to fix travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2dc898c2..e66501f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,8 @@ sudo: false python: - "2.7" - pypy +before_install: + - "sudo apt-get install -y xclip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - "pip install --upgrade --src . -r requirements.txt" -- cgit v1.2.3 From c97fe682303dbaeca551fd2c200a9f11e17749c6 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 16:48:49 -0300 Subject: trying to fix travis take 2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e66501f1..a4215e68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: python -sudo: false +sudo: true python: - "2.7" - pypy -- cgit v1.2.3 From 0a2d2d93903ccc730cc7c2ca52f57a276d75bf83 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 08:46:10 -0300 Subject: removed pyperclip hard dependencies --- .travis.yml | 4 +--- libmproxy/console/flowlist.py | 28 +++++++++++++++++----------- libmproxy/console/flowview.py | 28 +++++++++++++++++----------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4215e68..2dc898c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,8 @@ language: python -sudo: true +sudo: false python: - "2.7" - pypy -before_install: - - "sudo apt-get install -y xclip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - "pip install --upgrade --src . -r requirements.txt" diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 236bd508..d611dc6e 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,7 +1,10 @@ from __future__ import absolute_import import urwid -import pyperclip from . import common +try: + import pyperclip +except: + pyperclip = False def _mkhelp(): text = [] @@ -139,16 +142,19 @@ class ConnectionItem(common.WWrap): self.master.server_playback_path ) def server_copy_response(self, k): - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") + if pyperclip: + if k == "c": + try: + pyperclip.copy(self.flow.response.get_decoded_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(str(self.flow.response.headers)) + except TypeError: + self.master.statusbar.message("Error converting headers to text") + else: + self.master.statusbar.message("No clipboard support on your system, sorry.") def keypress(self, (maxcol,), key): key = common.shortcuts(key) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 08a0148f..667a7407 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -4,7 +4,10 @@ import urwid from . import common, grideditor, contentview from .. import utils, flow, controller from ..protocol.http import HTTPResponse, CONTENT_MISSING, decoded -import pyperclip +try: + import pyperclip +except: + pyperclip = False class SearchError(Exception): pass @@ -650,16 +653,19 @@ class FlowView(common.WWrap): self.master.refresh_flow(self.flow) def server_copy_response(self, k): - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") + if pyperclip: + if k == "c": + try: + pyperclip.copy(self.flow.response.get_decoded_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(str(self.flow.response.headers)) + except TypeError: + self.master.statusbar.message("Error converting headers to text") + else: + self.master.statusbar.message("No clipboard support on your system, sorry.") def delete_body(self, t): if t == "m": -- cgit v1.2.3 From b77cd1af606997f81890c1542f69d11daeda53b6 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 09:36:59 -0300 Subject: extracted server_copy_response to common --- libmproxy/console/common.py | 20 +++++++++++++++++++- libmproxy/console/flowlist.py | 22 +++------------------- libmproxy/console/flowview.py | 24 ++++-------------------- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 3e6e5ccc..3ba89f8e 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -3,7 +3,10 @@ import urwid import urwid.util from .. import utils from ..protocol.http import CONTENT_MISSING - +try: + import pyperclip +except: + pyperclip = False VIEW_LIST = 0 VIEW_FLOW = 1 @@ -161,6 +164,21 @@ def raw_format_flow(f, focus, extended, padding): pile.append(urwid.Columns(resp, dividechars=1)) return urwid.Pile(pile) +def server_copy_response( k, response, statusbar): + if pyperclip: + if k == "c": + try: + pyperclip.copy(response.get_decoded_content()) + except TypeError: + statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(str(response.headers)) + except TypeError: + statusbar.message("Error converting headers to text") + else: + statusbar.message("No clipboard support on your system, sorry.") + class FlowCache: @utils.LRUCache(200) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index d611dc6e..2dc20544 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,10 +1,6 @@ from __future__ import absolute_import import urwid from . import common -try: - import pyperclip -except: - pyperclip = False def _mkhelp(): text = [] @@ -141,20 +137,6 @@ class ConnectionItem(common.WWrap): self.state.last_saveload, self.master.server_playback_path ) - def server_copy_response(self, k): - if pyperclip: - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") - else: - self.master.statusbar.message("No clipboard support on your system, sorry.") def keypress(self, (maxcol,), key): key = common.shortcuts(key) @@ -228,7 +210,9 @@ class ConnectionItem(common.WWrap): ("content", "c"), ("headers", "h"), ), - self.server_copy_response, + common.server_copy_response, + self.flow.response, + self.master.statusbar ) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 667a7407..abca2ed6 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -4,10 +4,7 @@ import urwid from . import common, grideditor, contentview from .. import utils, flow, controller from ..protocol.http import HTTPResponse, CONTENT_MISSING, decoded -try: - import pyperclip -except: - pyperclip = False + class SearchError(Exception): pass @@ -652,21 +649,6 @@ class FlowView(common.WWrap): ) self.master.refresh_flow(self.flow) - def server_copy_response(self, k): - if pyperclip: - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") - else: - self.master.statusbar.message("No clipboard support on your system, sorry.") - def delete_body(self, t): if t == "m": val = CONTENT_MISSING @@ -777,7 +759,9 @@ class FlowView(common.WWrap): ("content", "c"), ("headers", "h"), ), - self.server_copy_response, + common.server_copy_response, + self.flow.response, + self.master.statusbar ) elif key == "m": p = list(contentview.view_prompts) -- cgit v1.2.3 From affb57ed08ca5167d38a21affeb84d8de2a77501 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 12:37:26 -0300 Subject: added support for saving file if content is binary. still wip --- libmproxy/console/common.py | 44 +++++++++++++++++++++++++++++++++++++++---- libmproxy/console/flowlist.py | 3 ++- libmproxy/console/flowview.py | 3 ++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 3ba89f8e..84dc8aef 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import urwid import urwid.util +import os from .. import utils from ..protocol.http import CONTENT_MISSING try: @@ -164,20 +165,55 @@ def raw_format_flow(f, focus, extended, padding): pile.append(urwid.Columns(resp, dividechars=1)) return urwid.Pile(pile) -def server_copy_response( k, response, statusbar): +## common save body parts +def _save_body(path, master, state, content): + if not path: + return + state.last_saveload = path + path = os.path.expanduser(path) + try: + f = file(path, "wb") + f.write(str(content)) + f.close() + except IOError, v: + master.statusbar.message(v.strerror) + +def save_body(k, master, state, content): + if k == "y": + master.path_prompt( + "Save response body: ", + state.last_saveload, + _save_body, + master, + state, + content, + ) + +## common server_copy_response parts +def server_copy_response( k, master, state, response): if pyperclip: if k == "c": try: pyperclip.copy(response.get_decoded_content()) except TypeError: - statusbar.message("Content is binary or can be converted to text") + master.prompt_onekey( + "Content is binary do you want to save it to a file instead?", + ( + ("yes", "y"), + ("no", "n"), + ), + save_body, + master, + state, + response.get_decoded_content(), + ) elif k == "h": try: pyperclip.copy(str(response.headers)) except TypeError: - statusbar.message("Error converting headers to text") + master.statusbar.message("Error converting headers to text") else: - statusbar.message("No clipboard support on your system, sorry.") + master.statusbar.message("No clipboard support on your system, sorry.") class FlowCache: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 2dc20544..214c10db 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -211,8 +211,9 @@ class ConnectionItem(common.WWrap): ("headers", "h"), ), common.server_copy_response, + self.master, + self.state, self.flow.response, - self.master.statusbar ) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index abca2ed6..bc0b5f83 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -760,8 +760,9 @@ class FlowView(common.WWrap): ("headers", "h"), ), common.server_copy_response, + self.master, + self.state, self.flow.response, - self.master.statusbar ) elif key == "m": p = list(contentview.view_prompts) -- cgit v1.2.3 From 7ba7d64bacc36821eddaaf2862f7a098949b2d4e Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 12:57:00 -0300 Subject: used save_body from common when b key is pressed --- libmproxy/console/common.py | 8 ++++---- libmproxy/console/flowview.py | 41 ++++++++++++++--------------------------- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 84dc8aef..29e59373 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -166,7 +166,7 @@ def raw_format_flow(f, focus, extended, padding): return urwid.Pile(pile) ## common save body parts -def _save_body(path, master, state, content): +def save_body(path, master, state, content): if not path: return state.last_saveload = path @@ -178,12 +178,12 @@ def _save_body(path, master, state, content): except IOError, v: master.statusbar.message(v.strerror) -def save_body(k, master, state, content): +def ask_save_body(k, master, state, content): if k == "y": master.path_prompt( "Save response body: ", state.last_saveload, - _save_body, + save_body, master, state, content, @@ -202,7 +202,7 @@ def server_copy_response( k, master, state, response): ("yes", "y"), ("no", "n"), ), - save_body, + ask_save_body, master, state, response.get_decoded_content(), diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index bc0b5f83..b964b92a 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -508,22 +508,6 @@ class FlowView(common.WWrap): self.flow.request.method = i[0].upper() self.master.refresh_flow(self.flow) - def save_body(self, path): - if not path: - return - self.state.last_saveload = path - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - c = self.flow.request - else: - c = self.flow.response - path = os.path.expanduser(path) - try: - f = file(path, "wb") - f.write(str(c.content)) - f.close() - except IOError, v: - self.master.statusbar.message(v.strerror) - def set_url(self, url): request = self.flow.request try: @@ -691,17 +675,20 @@ class FlowView(common.WWrap): elif key == "b": if conn: if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.path_prompt( - "Save request body: ", - self.state.last_saveload, - self.save_body - ) - else: - self.master.path_prompt( - "Save response body: ", - self.state.last_saveload, - self.save_body - ) + msg = "Save request body: " + content = self.flow.request.content + else: + msg = "Save response body: " + content = self.flow.response.content + + self.master.path_prompt( + msg, + self.state.last_saveload, + common.save_body, + self.master, + self.state, + content, + ) elif key == "d": if self.state.flow_count() == 1: self.master.view_flowlist() -- cgit v1.2.3 From d80e2e2b2b125a6b38baef6e9ba6d4282354775a Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Fri, 16 Jan 2015 12:13:55 -0300 Subject: added support for copying request (content|header) to clipboard --- libmproxy/console/common.py | 13 ++++++------- libmproxy/console/flowlist.py | 15 ++++++++++++++- libmproxy/console/flowview.py | 15 ++++++++++++++- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 29e59373..33738c0a 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -181,7 +181,7 @@ def save_body(path, master, state, content): def ask_save_body(k, master, state, content): if k == "y": master.path_prompt( - "Save response body: ", + "Save message content: ", state.last_saveload, save_body, master, @@ -189,12 +189,12 @@ def ask_save_body(k, master, state, content): content, ) -## common server_copy_response parts -def server_copy_response( k, master, state, response): +## common copy_message parts +def copy_message( k, master, state, message): if pyperclip: if k == "c": try: - pyperclip.copy(response.get_decoded_content()) + pyperclip.copy(message.get_decoded_content()) except TypeError: master.prompt_onekey( "Content is binary do you want to save it to a file instead?", @@ -205,17 +205,16 @@ def server_copy_response( k, master, state, response): ask_save_body, master, state, - response.get_decoded_content(), + message.get_decoded_content(), ) elif k == "h": try: - pyperclip.copy(str(response.headers)) + pyperclip.copy(str(message.headers)) except TypeError: master.statusbar.message("Error converting headers to text") else: master.statusbar.message("No clipboard support on your system, sorry.") - class FlowCache: @utils.LRUCache(200) def format_flow(self, *args): diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 214c10db..77803a51 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -13,6 +13,7 @@ def _mkhelp(): ("e", "toggle eventlog"), ("F", "toggle follow flow list"), ("g", "copy response(content/headers) to clipboard"), + ("G", "copy request(content/headers) to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -210,11 +211,23 @@ class ConnectionItem(common.WWrap): ("content", "c"), ("headers", "h"), ), - common.server_copy_response, + common.copy_message, self.master, self.state, self.flow.response, ) + elif key == "G": + self.master.prompt_onekey( + "Copy Request", + ( + ("content", "c"), + ("headers", "h"), + ), + common.copy_message, + self.master, + self.state, + self.flow.request, + ) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b964b92a..a759f109 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -20,6 +20,7 @@ def _mkhelp(): ("e", "edit request/response"), ("f", "load full body data"), ("g", "copy response(content/headers) to clipboard"), + ("G", "copy request(content/headers) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + @@ -746,11 +747,23 @@ class FlowView(common.WWrap): ("content", "c"), ("headers", "h"), ), - common.server_copy_response, + common.copy_message, self.master, self.state, self.flow.response, ) + elif key == "G": + self.master.prompt_onekey( + "Copy Request", + ( + ("content", "c"), + ("headers", "h"), + ), + common.copy_message, + self.master, + self.state, + self.flow.request, + ) elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) -- cgit v1.2.3 From e5922ae30ad1074fd2412019db3d6dff9cc010a1 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Fri, 16 Jan 2015 13:08:25 -0300 Subject: added support for 'b' key in flowlist --- libmproxy/console/common.py | 28 ++++++++++++++++++++++++++++ libmproxy/console/flowlist.py | 13 +++++++++++++ 2 files changed, 41 insertions(+) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 33738c0a..2f6c909c 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -189,8 +189,36 @@ def ask_save_body(k, master, state, content): content, ) +def which_body_save(k, master, state, flow): + if k == "q": + master.path_prompt( + "Save request content: ", + state.last_saveload, + save_body, + master, + state, + flow.request.get_decoded_content(), + ) + elif k == "r": + if flow.response: + master.path_prompt( + "Save response content: ", + state.last_saveload, + save_body, + master, + state, + flow.response.get_decoded_content(), + ) + else: + master.statusbar.message("Flow has no response") + ## common copy_message parts def copy_message( k, master, state, message): + if not message: + # only response could be None + master.statusbar.message("Flow has no response") + return + if pyperclip: if k == "c": try: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 77803a51..8fc9c616 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -7,6 +7,7 @@ def _mkhelp(): keys = [ ("A", "accept all intercepted flows"), ("a", "accept this intercepted flow"), + ("b", "save request/response body"), ("C", "clear flow list or eventlog"), ("d", "delete flow"), ("D", "duplicate flow"), @@ -228,6 +229,18 @@ class ConnectionItem(common.WWrap): self.state, self.flow.request, ) + elif key == "b": + self.master.prompt_onekey( + "Save", + ( + ("request", "q"), + ("response", "r"), + ), + common.which_body_save, + self.master, + self.state, + self.flow, + ) else: return key -- cgit v1.2.3 From 82d8c93261c6efe8314e68a34070ce960f308972 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 3 Feb 2015 15:41:09 -0300 Subject: added copy to clipboard support for url --- libmproxy/console/common.py | 5 +++++ libmproxy/console/flowlist.py | 3 ++- libmproxy/console/flowview.py | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 2f6c909c..b7c46476 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -240,6 +240,11 @@ def copy_message( k, master, state, message): pyperclip.copy(str(message.headers)) except TypeError: master.statusbar.message("Error converting headers to text") + elif k == "u": + try: + pyperclip.copy(message.url) + except TypeError: + master.statusbar.message("Error copying url to clipboard") else: master.statusbar.message("No clipboard support on your system, sorry.") diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 8fc9c616..fa430fdd 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -14,7 +14,7 @@ def _mkhelp(): ("e", "toggle eventlog"), ("F", "toggle follow flow list"), ("g", "copy response(content/headers) to clipboard"), - ("G", "copy request(content/headers) to clipboard"), + ("G", "copy request(content/headers/url) to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -223,6 +223,7 @@ class ConnectionItem(common.WWrap): ( ("content", "c"), ("headers", "h"), + ("url", "u"), ), common.copy_message, self.master, diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index a759f109..c01bb08f 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -20,7 +20,7 @@ def _mkhelp(): ("e", "edit request/response"), ("f", "load full body data"), ("g", "copy response(content/headers) to clipboard"), - ("G", "copy request(content/headers) to clipboard"), + ("G", "copy request(content/headers/url) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + @@ -758,6 +758,7 @@ class FlowView(common.WWrap): ( ("content", "c"), ("headers", "h"), + ("url", "u"), ), common.copy_message, self.master, -- cgit v1.2.3 From 4a481814f6ffca51feaadadec8239f0e6249ba26 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 13 Jan 2015 23:18:28 -0300 Subject: added pyperclip dependency --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 953df2bb..f9c8d15e 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,8 @@ deps = { "pyasn1>0.1.2", "pyOpenSSL>=0.14", "tornado>=4.0.2", - "configargparse>=0.9.3" + "configargparse>=0.9.3", + "pyperclip>=1.5.7" } script_deps = { "mitmproxy": { -- cgit v1.2.3 From f89a5235d36db8c82ec608ba1f39809d2a355384 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 10:52:52 -0300 Subject: wip - content copy is working, header representation is not --- libmproxy/console/flowlist.py | 16 ++++++++++++++++ libmproxy/protocol/http.py | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 102fa7b9..cdb4af49 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import urwid +import pyperclip from . import common def _mkhelp(): @@ -138,6 +139,11 @@ class ConnectionItem(common.WWrap): self.state.last_saveload, self.master.server_playback_path ) + def server_copy_response(self, k): + if k == "c": + pyperclip.copy(self.flow.response_content()) + elif k == "t": + pyperclip.copy(self.flow.response_headers()) def keypress(self, (maxcol,), key): key = common.shortcuts(key) @@ -204,6 +210,16 @@ class ConnectionItem(common.WWrap): self.master.run_script_once, self.flow ) + elif key == "g": + #copy flow part + self.master.prompt_onekey( + "Copy Response", + ( + ("content", "c"), + ("headers", "h"), + ), + self.server_copy_response, + ) else: return key diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index bebb4f7b..04e3fe40 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -953,6 +953,21 @@ class HTTPFlow(Flow): c += self.response.replace(pattern, repl, *args, **kwargs) return c + def response_content(self): + s = "[No Content]" + with decoded(self.response): + s = self.response.content + return s + + def response_headers(self): + with decoded(self.response): + sh = "" + for i in self.flow.response.headers: + v = self.flow.response.headers[i] + for j in v: + sh += str(i)+"="+str(v[j])+"\n" + return sh + class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): -- cgit v1.2.3 From ee75a0b9cbe5f4882453d2f1cb0d0a7df431200a Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 12:03:40 -0300 Subject: now content and header are working and exception for binary files are handled correctly --- libmproxy/console/flowlist.py | 13 ++++++++++--- libmproxy/protocol/http.py | 14 ++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index cdb4af49..98b5561f 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -13,6 +13,7 @@ def _mkhelp(): ("D", "duplicate flow"), ("e", "toggle eventlog"), ("F", "toggle follow flow list"), + ("g", "copy response(content/headers) to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -141,9 +142,15 @@ class ConnectionItem(common.WWrap): ) def server_copy_response(self, k): if k == "c": - pyperclip.copy(self.flow.response_content()) - elif k == "t": - pyperclip.copy(self.flow.response_headers()) + try: + pyperclip.copy(self.flow.response_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(self.flow.response_headers()) + except TypeError: + self.master.statusbar.message("Error converting headers to text") def keypress(self, (maxcol,), key): key = common.shortcuts(key) diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 04e3fe40..63f9e47b 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -954,20 +954,18 @@ class HTTPFlow(Flow): return c def response_content(self): - s = "[No Content]" with decoded(self.response): s = self.response.content + if s == None: + s = "[No content]" return s def response_headers(self): with decoded(self.response): - sh = "" - for i in self.flow.response.headers: - v = self.flow.response.headers[i] - for j in v: - sh += str(i)+"="+str(v[j])+"\n" - return sh - + s = str(self.response.headers) + if s == None: + s = "[]" + return s class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): -- cgit v1.2.3 From fdd012bdd80b0a1419e8967f10c92a9384a72da5 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 12:09:14 -0300 Subject: removed invalid comment and unneeded safe text --- libmproxy/console/flowlist.py | 1 - libmproxy/protocol/http.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 98b5561f..03dfe5ed 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -218,7 +218,6 @@ class ConnectionItem(common.WWrap): self.flow ) elif key == "g": - #copy flow part self.master.prompt_onekey( "Copy Response", ( diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 63f9e47b..f59b76ad 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -956,15 +956,11 @@ class HTTPFlow(Flow): def response_content(self): with decoded(self.response): s = self.response.content - if s == None: - s = "[No content]" return s def response_headers(self): with decoded(self.response): s = str(self.response.headers) - if s == None: - s = "[]" return s class HttpAuthenticationError(Exception): -- cgit v1.2.3 From 1a06f15ee0423941e906f6fc654094b0fa9a9e3a Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 12:36:19 -0300 Subject: added copy functionality to flowview too --- libmproxy/console/flowview.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 9e305b8a..25b085c3 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -4,7 +4,7 @@ import urwid from . import common, grideditor, contentview from .. import utils, flow, controller from ..protocol.http import HTTPResponse, CONTENT_MISSING, decoded - +import pyperclip class SearchError(Exception): pass @@ -19,6 +19,7 @@ def _mkhelp(): ("D", "duplicate flow"), ("e", "edit request/response"), ("f", "load full body data"), + ("g", "copy response(content/headers) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + @@ -648,6 +649,18 @@ class FlowView(common.WWrap): ) self.master.refresh_flow(self.flow) + def server_copy_response(self, k): + if k == "c": + try: + pyperclip.copy(self.flow.response_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(self.flow.response_headers()) + except TypeError: + self.master.statusbar.message("Error converting headers to text") + def delete_body(self, t): if t == "m": val = CONTENT_MISSING @@ -751,6 +764,15 @@ class FlowView(common.WWrap): ) self.master.refresh_flow(self.flow) self.master.statusbar.message("") + elif key == "g": + self.master.prompt_onekey( + "Copy Response", + ( + ("content", "c"), + ("headers", "h"), + ), + self.server_copy_response, + ) elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) -- cgit v1.2.3 From d9f562b5c0ba0b4769455c117c1321d63ff6497c Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 14:45:19 -0300 Subject: used get_decoded_content and removed decode call from headers as max suggested --- libmproxy/console/flowlist.py | 4 ++-- libmproxy/console/flowview.py | 4 ++-- libmproxy/protocol/http.py | 10 ---------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 03dfe5ed..44b32855 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -143,12 +143,12 @@ class ConnectionItem(common.WWrap): def server_copy_response(self, k): if k == "c": try: - pyperclip.copy(self.flow.response_content()) + pyperclip.copy(self.flow.response.get_decoded_content()) except TypeError: self.master.statusbar.message("Content is binary or can be converted to text") elif k == "h": try: - pyperclip.copy(self.flow.response_headers()) + pyperclip.copy(str(self.flow.response.headers)) except TypeError: self.master.statusbar.message("Error converting headers to text") diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 25b085c3..08a0148f 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -652,12 +652,12 @@ class FlowView(common.WWrap): def server_copy_response(self, k): if k == "c": try: - pyperclip.copy(self.flow.response_content()) + pyperclip.copy(self.flow.response.get_decoded_content()) except TypeError: self.master.statusbar.message("Content is binary or can be converted to text") elif k == "h": try: - pyperclip.copy(self.flow.response_headers()) + pyperclip.copy(str(self.flow.response.headers)) except TypeError: self.master.statusbar.message("Error converting headers to text") diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index f59b76ad..284731b0 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -953,16 +953,6 @@ class HTTPFlow(Flow): c += self.response.replace(pattern, repl, *args, **kwargs) return c - def response_content(self): - with decoded(self.response): - s = self.response.content - return s - - def response_headers(self): - with decoded(self.response): - s = str(self.response.headers) - return s - class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): super(HttpAuthenticationError, self).__init__( -- cgit v1.2.3 From 470d8e925a10cef73e684c6fd65731d20e654519 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 16:44:59 -0300 Subject: trying to fix travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2dc898c2..e66501f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,8 @@ sudo: false python: - "2.7" - pypy +before_install: + - "sudo apt-get install -y xclip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - "pip install --upgrade --src . -r requirements.txt" -- cgit v1.2.3 From 8e1f260150f820cbba35cd464a639f09a47c611e Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 14 Jan 2015 16:48:49 -0300 Subject: trying to fix travis take 2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e66501f1..a4215e68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: python -sudo: false +sudo: true python: - "2.7" - pypy -- cgit v1.2.3 From f21a44dd48a1ea7401378830fc38e5a864e927e5 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 08:46:10 -0300 Subject: removed pyperclip hard dependencies --- .travis.yml | 4 +--- libmproxy/console/flowlist.py | 28 +++++++++++++++++----------- libmproxy/console/flowview.py | 28 +++++++++++++++++----------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4215e68..2dc898c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,8 @@ language: python -sudo: true +sudo: false python: - "2.7" - pypy -before_install: - - "sudo apt-get install -y xclip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - "pip install --upgrade --src . -r requirements.txt" diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 44b32855..f97a7a11 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,7 +1,10 @@ from __future__ import absolute_import import urwid -import pyperclip from . import common +try: + import pyperclip +except: + pyperclip = False def _mkhelp(): text = [] @@ -141,16 +144,19 @@ class ConnectionItem(common.WWrap): self.master.server_playback_path ) def server_copy_response(self, k): - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") + if pyperclip: + if k == "c": + try: + pyperclip.copy(self.flow.response.get_decoded_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(str(self.flow.response.headers)) + except TypeError: + self.master.statusbar.message("Error converting headers to text") + else: + self.master.statusbar.message("No clipboard support on your system, sorry.") def keypress(self, (maxcol,), key): key = common.shortcuts(key) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 08a0148f..667a7407 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -4,7 +4,10 @@ import urwid from . import common, grideditor, contentview from .. import utils, flow, controller from ..protocol.http import HTTPResponse, CONTENT_MISSING, decoded -import pyperclip +try: + import pyperclip +except: + pyperclip = False class SearchError(Exception): pass @@ -650,16 +653,19 @@ class FlowView(common.WWrap): self.master.refresh_flow(self.flow) def server_copy_response(self, k): - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") + if pyperclip: + if k == "c": + try: + pyperclip.copy(self.flow.response.get_decoded_content()) + except TypeError: + self.master.statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(str(self.flow.response.headers)) + except TypeError: + self.master.statusbar.message("Error converting headers to text") + else: + self.master.statusbar.message("No clipboard support on your system, sorry.") def delete_body(self, t): if t == "m": -- cgit v1.2.3 From c57efffe01bdc29e08b5eaa1a9b7071336bd4bb1 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 09:36:59 -0300 Subject: extracted server_copy_response to common --- libmproxy/console/common.py | 20 +++++++++++++++++++- libmproxy/console/flowlist.py | 22 +++------------------- libmproxy/console/flowview.py | 24 ++++-------------------- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 3e6e5ccc..3ba89f8e 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -3,7 +3,10 @@ import urwid import urwid.util from .. import utils from ..protocol.http import CONTENT_MISSING - +try: + import pyperclip +except: + pyperclip = False VIEW_LIST = 0 VIEW_FLOW = 1 @@ -161,6 +164,21 @@ def raw_format_flow(f, focus, extended, padding): pile.append(urwid.Columns(resp, dividechars=1)) return urwid.Pile(pile) +def server_copy_response( k, response, statusbar): + if pyperclip: + if k == "c": + try: + pyperclip.copy(response.get_decoded_content()) + except TypeError: + statusbar.message("Content is binary or can be converted to text") + elif k == "h": + try: + pyperclip.copy(str(response.headers)) + except TypeError: + statusbar.message("Error converting headers to text") + else: + statusbar.message("No clipboard support on your system, sorry.") + class FlowCache: @utils.LRUCache(200) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index f97a7a11..b2e2ba07 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,10 +1,6 @@ from __future__ import absolute_import import urwid from . import common -try: - import pyperclip -except: - pyperclip = False def _mkhelp(): text = [] @@ -143,20 +139,6 @@ class ConnectionItem(common.WWrap): self.state.last_saveload, self.master.server_playback_path ) - def server_copy_response(self, k): - if pyperclip: - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") - else: - self.master.statusbar.message("No clipboard support on your system, sorry.") def keypress(self, (maxcol,), key): key = common.shortcuts(key) @@ -230,7 +212,9 @@ class ConnectionItem(common.WWrap): ("content", "c"), ("headers", "h"), ), - self.server_copy_response, + common.server_copy_response, + self.flow.response, + self.master.statusbar ) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 667a7407..abca2ed6 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -4,10 +4,7 @@ import urwid from . import common, grideditor, contentview from .. import utils, flow, controller from ..protocol.http import HTTPResponse, CONTENT_MISSING, decoded -try: - import pyperclip -except: - pyperclip = False + class SearchError(Exception): pass @@ -652,21 +649,6 @@ class FlowView(common.WWrap): ) self.master.refresh_flow(self.flow) - def server_copy_response(self, k): - if pyperclip: - if k == "c": - try: - pyperclip.copy(self.flow.response.get_decoded_content()) - except TypeError: - self.master.statusbar.message("Content is binary or can be converted to text") - elif k == "h": - try: - pyperclip.copy(str(self.flow.response.headers)) - except TypeError: - self.master.statusbar.message("Error converting headers to text") - else: - self.master.statusbar.message("No clipboard support on your system, sorry.") - def delete_body(self, t): if t == "m": val = CONTENT_MISSING @@ -777,7 +759,9 @@ class FlowView(common.WWrap): ("content", "c"), ("headers", "h"), ), - self.server_copy_response, + common.server_copy_response, + self.flow.response, + self.master.statusbar ) elif key == "m": p = list(contentview.view_prompts) -- cgit v1.2.3 From 8f66fe1bfc16d0bb63acc267632471640939371e Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 12:37:26 -0300 Subject: added support for saving file if content is binary. still wip --- libmproxy/console/common.py | 44 +++++++++++++++++++++++++++++++++++++++---- libmproxy/console/flowlist.py | 3 ++- libmproxy/console/flowview.py | 3 ++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 3ba89f8e..84dc8aef 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import urwid import urwid.util +import os from .. import utils from ..protocol.http import CONTENT_MISSING try: @@ -164,20 +165,55 @@ def raw_format_flow(f, focus, extended, padding): pile.append(urwid.Columns(resp, dividechars=1)) return urwid.Pile(pile) -def server_copy_response( k, response, statusbar): +## common save body parts +def _save_body(path, master, state, content): + if not path: + return + state.last_saveload = path + path = os.path.expanduser(path) + try: + f = file(path, "wb") + f.write(str(content)) + f.close() + except IOError, v: + master.statusbar.message(v.strerror) + +def save_body(k, master, state, content): + if k == "y": + master.path_prompt( + "Save response body: ", + state.last_saveload, + _save_body, + master, + state, + content, + ) + +## common server_copy_response parts +def server_copy_response( k, master, state, response): if pyperclip: if k == "c": try: pyperclip.copy(response.get_decoded_content()) except TypeError: - statusbar.message("Content is binary or can be converted to text") + master.prompt_onekey( + "Content is binary do you want to save it to a file instead?", + ( + ("yes", "y"), + ("no", "n"), + ), + save_body, + master, + state, + response.get_decoded_content(), + ) elif k == "h": try: pyperclip.copy(str(response.headers)) except TypeError: - statusbar.message("Error converting headers to text") + master.statusbar.message("Error converting headers to text") else: - statusbar.message("No clipboard support on your system, sorry.") + master.statusbar.message("No clipboard support on your system, sorry.") class FlowCache: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index b2e2ba07..62c031b6 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -213,8 +213,9 @@ class ConnectionItem(common.WWrap): ("headers", "h"), ), common.server_copy_response, + self.master, + self.state, self.flow.response, - self.master.statusbar ) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index abca2ed6..bc0b5f83 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -760,8 +760,9 @@ class FlowView(common.WWrap): ("headers", "h"), ), common.server_copy_response, + self.master, + self.state, self.flow.response, - self.master.statusbar ) elif key == "m": p = list(contentview.view_prompts) -- cgit v1.2.3 From 3bcf0cbba894ad12d4cfc438d26cdf22d640416c Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 15 Jan 2015 12:57:00 -0300 Subject: used save_body from common when b key is pressed --- libmproxy/console/common.py | 8 ++++---- libmproxy/console/flowview.py | 41 ++++++++++++++--------------------------- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 84dc8aef..29e59373 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -166,7 +166,7 @@ def raw_format_flow(f, focus, extended, padding): return urwid.Pile(pile) ## common save body parts -def _save_body(path, master, state, content): +def save_body(path, master, state, content): if not path: return state.last_saveload = path @@ -178,12 +178,12 @@ def _save_body(path, master, state, content): except IOError, v: master.statusbar.message(v.strerror) -def save_body(k, master, state, content): +def ask_save_body(k, master, state, content): if k == "y": master.path_prompt( "Save response body: ", state.last_saveload, - _save_body, + save_body, master, state, content, @@ -202,7 +202,7 @@ def server_copy_response( k, master, state, response): ("yes", "y"), ("no", "n"), ), - save_body, + ask_save_body, master, state, response.get_decoded_content(), diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index bc0b5f83..b964b92a 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -508,22 +508,6 @@ class FlowView(common.WWrap): self.flow.request.method = i[0].upper() self.master.refresh_flow(self.flow) - def save_body(self, path): - if not path: - return - self.state.last_saveload = path - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - c = self.flow.request - else: - c = self.flow.response - path = os.path.expanduser(path) - try: - f = file(path, "wb") - f.write(str(c.content)) - f.close() - except IOError, v: - self.master.statusbar.message(v.strerror) - def set_url(self, url): request = self.flow.request try: @@ -691,17 +675,20 @@ class FlowView(common.WWrap): elif key == "b": if conn: if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.path_prompt( - "Save request body: ", - self.state.last_saveload, - self.save_body - ) - else: - self.master.path_prompt( - "Save response body: ", - self.state.last_saveload, - self.save_body - ) + msg = "Save request body: " + content = self.flow.request.content + else: + msg = "Save response body: " + content = self.flow.response.content + + self.master.path_prompt( + msg, + self.state.last_saveload, + common.save_body, + self.master, + self.state, + content, + ) elif key == "d": if self.state.flow_count() == 1: self.master.view_flowlist() -- cgit v1.2.3 From 9fc68d320c80ad07398a234630f6b59546a444e0 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Fri, 16 Jan 2015 12:13:55 -0300 Subject: added support for copying request (content|header) to clipboard --- libmproxy/console/common.py | 13 ++++++------- libmproxy/console/flowlist.py | 15 ++++++++++++++- libmproxy/console/flowview.py | 15 ++++++++++++++- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 29e59373..33738c0a 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -181,7 +181,7 @@ def save_body(path, master, state, content): def ask_save_body(k, master, state, content): if k == "y": master.path_prompt( - "Save response body: ", + "Save message content: ", state.last_saveload, save_body, master, @@ -189,12 +189,12 @@ def ask_save_body(k, master, state, content): content, ) -## common server_copy_response parts -def server_copy_response( k, master, state, response): +## common copy_message parts +def copy_message( k, master, state, message): if pyperclip: if k == "c": try: - pyperclip.copy(response.get_decoded_content()) + pyperclip.copy(message.get_decoded_content()) except TypeError: master.prompt_onekey( "Content is binary do you want to save it to a file instead?", @@ -205,17 +205,16 @@ def server_copy_response( k, master, state, response): ask_save_body, master, state, - response.get_decoded_content(), + message.get_decoded_content(), ) elif k == "h": try: - pyperclip.copy(str(response.headers)) + pyperclip.copy(str(message.headers)) except TypeError: master.statusbar.message("Error converting headers to text") else: master.statusbar.message("No clipboard support on your system, sorry.") - class FlowCache: @utils.LRUCache(200) def format_flow(self, *args): diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 62c031b6..6939be23 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -13,6 +13,7 @@ def _mkhelp(): ("e", "toggle eventlog"), ("F", "toggle follow flow list"), ("g", "copy response(content/headers) to clipboard"), + ("G", "copy request(content/headers) to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -212,11 +213,23 @@ class ConnectionItem(common.WWrap): ("content", "c"), ("headers", "h"), ), - common.server_copy_response, + common.copy_message, self.master, self.state, self.flow.response, ) + elif key == "G": + self.master.prompt_onekey( + "Copy Request", + ( + ("content", "c"), + ("headers", "h"), + ), + common.copy_message, + self.master, + self.state, + self.flow.request, + ) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b964b92a..a759f109 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -20,6 +20,7 @@ def _mkhelp(): ("e", "edit request/response"), ("f", "load full body data"), ("g", "copy response(content/headers) to clipboard"), + ("G", "copy request(content/headers) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + @@ -746,11 +747,23 @@ class FlowView(common.WWrap): ("content", "c"), ("headers", "h"), ), - common.server_copy_response, + common.copy_message, self.master, self.state, self.flow.response, ) + elif key == "G": + self.master.prompt_onekey( + "Copy Request", + ( + ("content", "c"), + ("headers", "h"), + ), + common.copy_message, + self.master, + self.state, + self.flow.request, + ) elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) -- cgit v1.2.3 From ae83d39eba4a5518537d799fc4bd61d083f32944 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Fri, 16 Jan 2015 13:08:25 -0300 Subject: added support for 'b' key in flowlist --- libmproxy/console/common.py | 28 ++++++++++++++++++++++++++++ libmproxy/console/flowlist.py | 13 +++++++++++++ 2 files changed, 41 insertions(+) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 33738c0a..2f6c909c 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -189,8 +189,36 @@ def ask_save_body(k, master, state, content): content, ) +def which_body_save(k, master, state, flow): + if k == "q": + master.path_prompt( + "Save request content: ", + state.last_saveload, + save_body, + master, + state, + flow.request.get_decoded_content(), + ) + elif k == "r": + if flow.response: + master.path_prompt( + "Save response content: ", + state.last_saveload, + save_body, + master, + state, + flow.response.get_decoded_content(), + ) + else: + master.statusbar.message("Flow has no response") + ## common copy_message parts def copy_message( k, master, state, message): + if not message: + # only response could be None + master.statusbar.message("Flow has no response") + return + if pyperclip: if k == "c": try: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 6939be23..4acb17dc 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -7,6 +7,7 @@ def _mkhelp(): keys = [ ("A", "accept all intercepted flows"), ("a", "accept this intercepted flow"), + ("b", "save request/response body"), ("C", "clear flow list or eventlog"), ("d", "delete flow"), ("D", "duplicate flow"), @@ -230,6 +231,18 @@ class ConnectionItem(common.WWrap): self.state, self.flow.request, ) + elif key == "b": + self.master.prompt_onekey( + "Save", + ( + ("request", "q"), + ("response", "r"), + ), + common.which_body_save, + self.master, + self.state, + self.flow, + ) else: return key -- cgit v1.2.3 From 75cca63b2687db5da0793c2e6d60d38531f18b59 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 3 Feb 2015 15:41:09 -0300 Subject: added copy to clipboard support for url --- libmproxy/console/common.py | 5 +++++ libmproxy/console/flowlist.py | 3 ++- libmproxy/console/flowview.py | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 2f6c909c..b7c46476 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -240,6 +240,11 @@ def copy_message( k, master, state, message): pyperclip.copy(str(message.headers)) except TypeError: master.statusbar.message("Error converting headers to text") + elif k == "u": + try: + pyperclip.copy(message.url) + except TypeError: + master.statusbar.message("Error copying url to clipboard") else: master.statusbar.message("No clipboard support on your system, sorry.") diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 4acb17dc..fbcf1052 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -14,7 +14,7 @@ def _mkhelp(): ("e", "toggle eventlog"), ("F", "toggle follow flow list"), ("g", "copy response(content/headers) to clipboard"), - ("G", "copy request(content/headers) to clipboard"), + ("G", "copy request(content/headers/url) to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -225,6 +225,7 @@ class ConnectionItem(common.WWrap): ( ("content", "c"), ("headers", "h"), + ("url", "u"), ), common.copy_message, self.master, diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index a759f109..c01bb08f 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -20,7 +20,7 @@ def _mkhelp(): ("e", "edit request/response"), ("f", "load full body data"), ("g", "copy response(content/headers) to clipboard"), - ("G", "copy request(content/headers) to clipboard"), + ("G", "copy request(content/headers/url) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + @@ -758,6 +758,7 @@ class FlowView(common.WWrap): ( ("content", "c"), ("headers", "h"), + ("url", "u"), ), common.copy_message, self.master, -- cgit v1.2.3 From 64c02a16c389d4fdee396f132a76a627302c7511 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Fri, 6 Feb 2015 00:44:43 -0300 Subject: save_flow now uses with, and pyperclip requirement updated to 1.5.8 --- libmproxy/console/common.py | 5 ++--- setup.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index b7c46476..6141bc1c 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -172,9 +172,8 @@ def save_body(path, master, state, content): state.last_saveload = path path = os.path.expanduser(path) try: - f = file(path, "wb") - f.write(str(content)) - f.close() + with file(path, "wb") as f: + f.write(content) except IOError, v: master.statusbar.message(v.strerror) diff --git a/setup.py b/setup.py index f9c8d15e..9a19aab9 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ deps = { "pyOpenSSL>=0.14", "tornado>=4.0.2", "configargparse>=0.9.3", - "pyperclip>=1.5.7" + "pyperclip>=1.5.8" } script_deps = { "mitmproxy": { -- cgit v1.2.3 From f49dcb0d91031c75231b4659f141aece5a43f8d1 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Fri, 6 Feb 2015 00:59:05 -0300 Subject: removed str() cast and changed 'failed copy trying save instead' message --- libmproxy/console/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 6141bc1c..c0929d58 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -224,7 +224,7 @@ def copy_message( k, master, state, message): pyperclip.copy(message.get_decoded_content()) except TypeError: master.prompt_onekey( - "Content is binary do you want to save it to a file instead?", + "Cannot copy binary data to clipboard. Save as file?", ( ("yes", "y"), ("no", "n"), @@ -236,7 +236,7 @@ def copy_message( k, master, state, message): ) elif k == "h": try: - pyperclip.copy(str(message.headers)) + pyperclip.copy(message.headers) except TypeError: master.statusbar.message("Error converting headers to text") elif k == "u": -- cgit v1.2.3 From 02e0bad684d4405ca5ae2c8335661e2db20c9627 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 6 Feb 2015 23:32:22 +0100 Subject: improve clipboard UX --- libmproxy/console/common.py | 141 +++++++++++++++++++++++------------------- libmproxy/console/flowlist.py | 16 +---- libmproxy/console/flowview.py | 20 ++---- 3 files changed, 86 insertions(+), 91 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index c0929d58..aaec81b5 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -165,87 +165,104 @@ def raw_format_flow(f, focus, extended, padding): pile.append(urwid.Columns(resp, dividechars=1)) return urwid.Pile(pile) -## common save body parts -def save_body(path, master, state, content): + +# Save file to disk +def save_data(path, data, master, state): if not path: return state.last_saveload = path path = os.path.expanduser(path) try: with file(path, "wb") as f: - f.write(content) + f.write(data) except IOError, v: master.statusbar.message(v.strerror) -def ask_save_body(k, master, state, content): - if k == "y": - master.path_prompt( - "Save message content: ", - state.last_saveload, - save_body, - master, - state, - content, - ) -def which_body_save(k, master, state, flow): - if k == "q": - master.path_prompt( - "Save request content: ", - state.last_saveload, - save_body, - master, - state, - flow.request.get_decoded_content(), - ) - elif k == "r": - if flow.response: - master.path_prompt( - "Save response content: ", - state.last_saveload, - save_body, +def ask_save_path(prompt, data, master, state): + master.path_prompt( + prompt, + state.last_saveload, + save_data, + data, + master, + state + ) + + +def ask_save_body(part, master, state, flow): + """ + Save either the request or the response body to disk. + part can either be "q" (request), "s" (response) or None (ask user if necessary). + """ + + request_has_content = flow.request and flow.request.content + response_has_content = flow.response and flow.response.content + + if part is None: + # We first need to determine whether we want to save the request or the response content. + if request_has_content and response_has_content: + master.prompt_onekey( + "Save", + ( + ("request", "q"), + ("response", "s"), + ), + ask_save_body, master, state, - flow.response.get_decoded_content(), + flow ) + elif response_has_content: + ask_save_body("s", master, state, flow) else: - master.statusbar.message("Flow has no response") + ask_save_body("q", master, state, flow) + + elif part == "q" and request_has_content: + ask_save_path("Save request content: ", flow.request.get_decoded_content(), master, state) + elif part == "s" and response_has_content: + ask_save_path("Save response content: ", flow.response.get_decoded_content(), master, state) + else: + master.statusbar.message("No content to save.") -## common copy_message parts -def copy_message( k, master, state, message): + +# common copy_message parts +def copy_message(k, master, state, message): + if not pyperclip: + master.statusbar.message("No clipboard support on your system, sorry.") + return None if not message: # only response could be None - master.statusbar.message("Flow has no response") + master.statusbar.message("Flow has no response") return - if pyperclip: - if k == "c": - try: - pyperclip.copy(message.get_decoded_content()) - except TypeError: - master.prompt_onekey( - "Cannot copy binary data to clipboard. Save as file?", - ( - ("yes", "y"), - ("no", "n"), - ), - ask_save_body, - master, - state, - message.get_decoded_content(), - ) - elif k == "h": - try: - pyperclip.copy(message.headers) - except TypeError: - master.statusbar.message("Error converting headers to text") - elif k == "u": - try: - pyperclip.copy(message.url) - except TypeError: - master.statusbar.message("Error copying url to clipboard") - else: - master.statusbar.message("No clipboard support on your system, sorry.") + data = None + if k == "c": + data = message.get_decoded_content() + elif k == "h": + data = message.headers + elif k == "u": + data = message.url + + if not data: + master.statusbar.message("No content to copy.") + return + + try: + pyperclip.copy(data) + except TypeError: + def save(k): + if k == "y": + ask_save_path("Save data: ", data, master, state) + master.prompt_onekey( + "Cannot copy binary data to clipboard. Save as file?", + ( + ("yes", "y"), + ("no", "n"), + ), + save + ) + class FlowCache: @utils.LRUCache(200) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index fbcf1052..e5468be1 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -217,7 +217,7 @@ class ConnectionItem(common.WWrap): common.copy_message, self.master, self.state, - self.flow.response, + self.flow.response ) elif key == "G": self.master.prompt_onekey( @@ -230,20 +230,10 @@ class ConnectionItem(common.WWrap): common.copy_message, self.master, self.state, - self.flow.request, + self.flow.request ) elif key == "b": - self.master.prompt_onekey( - "Save", - ( - ("request", "q"), - ("response", "r"), - ), - common.which_body_save, - self.master, - self.state, - self.flow, - ) + common.ask_save_body(None, self.master, self.state, self.flow) else: return key diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index f95cd776..4e604b00 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -675,22 +675,10 @@ class FlowView(common.WWrap): self.master.accept_all() self.master.view_flow(self.flow) elif key == "b": - if conn: - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - msg = "Save request body: " - content = self.flow.request.content - else: - msg = "Save response body: " - content = self.flow.response.content - - self.master.path_prompt( - msg, - self.state.last_saveload, - common.save_body, - self.master, - self.state, - content, - ) + if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + common.ask_save_body("q", self.master, self.state, self.flow) + else: + common.ask_save_body("s", self.master, self.state, self.flow) elif key == "d": if self.state.flow_count() == 1: self.master.view_flowlist() -- cgit v1.2.3 From 65c14724f56d03f13439e980cbaddef3509f0b3c Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 7 Feb 2015 00:33:29 +0100 Subject: make copy context-sensitive --- libmproxy/console/common.py | 122 ++++++++++++++++++++++++++++-------------- libmproxy/console/flowlist.py | 28 +--------- libmproxy/console/flowview.py | 29 ++-------- 3 files changed, 89 insertions(+), 90 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index aaec81b5..e4a4acba 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -3,7 +3,8 @@ import urwid import urwid.util import os from .. import utils -from ..protocol.http import CONTENT_MISSING +from ..protocol.http import CONTENT_MISSING, decoded + try: import pyperclip except: @@ -190,6 +191,86 @@ def ask_save_path(prompt, data, master, state): ) +def copy_flow_format_data(part, scope, flow): + if part == "u": + data = flow.request.url + else: + data = "" + if scope in ("q", "a"): + with decoded(flow.request): + if part == "h": + data += flow.request.assemble() + elif part == "c": + data += flow.request.content + else: + raise ValueError("Unknown part: {}".format(part)) + if scope == "a" and flow.request.content and flow.response: + # Add padding between request and response + data += "\r\n" * 2 + if scope in ("s", "a") and flow.response: + with decoded(flow.response): + if part == "h": + data += flow.response.assemble() + elif part == "c": + data += flow.response.content + else: + raise ValueError("Unknown part: {}".format(part)) + return data + + +def copy_flow(part, scope, flow, master, state): + """ + part: _c_ontent, _a_ll, _u_rl + scope: _a_ll, re_q_uest, re_s_ponse + """ + data = copy_flow_format_data(part, scope, flow) + + if not data: + if scope == "q": + master.statusbar.message("No request content to copy.") + elif scope == "s": + master.statusbar.message("No response content to copy.") + else: + master.statusbar.message("No contents to copy.") + return + + try: + master.add_event(str(len(data))) + pyperclip.copy(data) + except RuntimeError: + def save(k): + if k == "y": + ask_save_path("Save data: ", data, master, state) + + master.prompt_onekey( + "Cannot copy binary data to clipboard. Save as file?", + ( + ("yes", "y"), + ("no", "n"), + ), + save + ) + + +def ask_copy_part(scope, flow, master, state): + choices = [ + ("content", "c"), + ("headers+content", "h") + ] + if scope != "s": + choices.append(("url", "u")) + + master.prompt_onekey( + "Copy", + choices, + copy_flow, + scope, + flow, + master, + state + ) + + def ask_save_body(part, master, state, flow): """ Save either the request or the response body to disk. @@ -226,44 +307,6 @@ def ask_save_body(part, master, state, flow): master.statusbar.message("No content to save.") -# common copy_message parts -def copy_message(k, master, state, message): - if not pyperclip: - master.statusbar.message("No clipboard support on your system, sorry.") - return None - if not message: - # only response could be None - master.statusbar.message("Flow has no response") - return - - data = None - if k == "c": - data = message.get_decoded_content() - elif k == "h": - data = message.headers - elif k == "u": - data = message.url - - if not data: - master.statusbar.message("No content to copy.") - return - - try: - pyperclip.copy(data) - except TypeError: - def save(k): - if k == "y": - ask_save_path("Save data: ", data, master, state) - master.prompt_onekey( - "Cannot copy binary data to clipboard. Save as file?", - ( - ("yes", "y"), - ("no", "n"), - ), - save - ) - - class FlowCache: @utils.LRUCache(200) def format_flow(self, *args): @@ -313,7 +356,6 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2): return flowcache.format_flow(tuple(sorted(d.items())), focus, extended, padding) - def int_version(v): SIG = 3 v = urwid.__version__.split("-")[0].split(".") diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index e5468be1..c5cef061 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -13,8 +13,7 @@ def _mkhelp(): ("D", "duplicate flow"), ("e", "toggle eventlog"), ("F", "toggle follow flow list"), - ("g", "copy response(content/headers) to clipboard"), - ("G", "copy request(content/headers/url) to clipboard"), + ("g", "copy flow to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), ("r", "replay request"), @@ -208,30 +207,7 @@ class ConnectionItem(common.WWrap): self.flow ) elif key == "g": - self.master.prompt_onekey( - "Copy Response", - ( - ("content", "c"), - ("headers", "h"), - ), - common.copy_message, - self.master, - self.state, - self.flow.response - ) - elif key == "G": - self.master.prompt_onekey( - "Copy Request", - ( - ("content", "c"), - ("headers", "h"), - ("url", "u"), - ), - common.copy_message, - self.master, - self.state, - self.flow.request - ) + common.ask_copy_part("a", self.flow, self.master, self.state) elif key == "b": common.ask_save_body(None, self.master, self.state, self.flow) else: diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 4e604b00..e04d6bcc 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -730,30 +730,11 @@ class FlowView(common.WWrap): self.master.refresh_flow(self.flow) self.master.statusbar.message("") elif key == "g": - self.master.prompt_onekey( - "Copy Response", - ( - ("content", "c"), - ("headers", "h"), - ), - common.copy_message, - self.master, - self.state, - self.flow.response, - ) - elif key == "G": - self.master.prompt_onekey( - "Copy Request", - ( - ("content", "c"), - ("headers", "h"), - ("url", "u"), - ), - common.copy_message, - self.master, - self.state, - self.flow.request, - ) + if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + scope = "q" + else: + scope = "s" + common.ask_copy_part(scope, self.flow, self.master, self.state) elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) -- cgit v1.2.3 From 102183fd23afceda84ca79bcc67305cf9f4e8369 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 7 Feb 2015 00:36:47 +0100 Subject: remove leftovers --- libmproxy/console/flowview.py | 1 - libmproxy/protocol/http.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index e04d6bcc..d5d41f7b 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -20,7 +20,6 @@ def _mkhelp(): ("e", "edit request/response"), ("f", "load full body data"), ("g", "copy response(content/headers) to clipboard"), - ("G", "copy request(content/headers/url) to clipboard"), ("m", "change body display mode for this entity"), (None, common.highlight_key("automatic", "a") + diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 284731b0..bebb4f7b 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -953,6 +953,7 @@ class HTTPFlow(Flow): c += self.response.replace(pattern, repl, *args, **kwargs) return c + class HttpAuthenticationError(Exception): def __init__(self, auth_headers=None): super(HttpAuthenticationError, self).__init__( -- cgit v1.2.3 From ba42984b593246b0105a077311e16a2ca71f79eb Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 10 Feb 2015 15:24:21 -0300 Subject: added support for creating new requests. still wip (not working for https) --- libmproxy/console/common.py | 11 +++++++++++ libmproxy/console/flowlist.py | 29 +++++++++++++++++++++++++++++ libmproxy/console/flowview.py | 14 ++------------ libmproxy/flow.py | 9 +++++++++ 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index e4a4acba..a2cfd57b 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -17,6 +17,17 @@ VIEW_FLOW = 1 VIEW_FLOW_REQUEST = 0 VIEW_FLOW_RESPONSE = 1 +METHOD_OPTIONS = [ + ("get", "g"), + ("post", "p"), + ("put", "u"), + ("head", "h"), + ("trace", "t"), + ("delete", "d"), + ("options", "o"), + ("edit raw", "e"), +] + def highlight_key(s, k): l = [] diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index c5cef061..8dfaba95 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import urwid +from netlib import http from . import common def _mkhelp(): @@ -16,6 +17,7 @@ def _mkhelp(): ("g", "copy flow to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), + ("n", "creates a new request"), ("r", "replay request"), ("V", "revert changes to request"), ("w", "save flows "), @@ -245,6 +247,31 @@ class FlowListBox(urwid.ListBox): self.master = master urwid.ListBox.__init__(self, master.flow_list_walker) + def get_method_raw(self, k): + if k: + self.get_url(k) + + def get_method(self, k): + if k == "e": + self.master.prompt("Method:", "", self.get_method_raw) + else: + method = "" + for i in common.METHOD_OPTIONS: + if i[1] == k: + method = i[0].upper() + self.get_url(method) + + def get_url(self,method): + self.master.prompt("Url:", "http://www.example.com/", self.new_request, method) + + def new_request(self, url, method): + try: + scheme, host, port, path = http.parse_url(url) + f = self.master.add_request(method, scheme, host, port, path) + self.master.view_flow(f) + except ValueError: + self.master.statusbar.message("Invalid Url") + def keypress(self, size, key): key = common.shortcuts(key) if key == "A": @@ -262,6 +289,8 @@ class FlowListBox(urwid.ListBox): self.master.state.last_saveload, self.master.load_flows_callback ) + elif key == "n": + self.master.prompt_onekey("Method", common.METHOD_OPTIONS, self.get_method) elif key == "F": self.master.toggle_follow_flows() elif key == "W": diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index d5d41f7b..5c91512c 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -109,16 +109,6 @@ cache = CallbackCache() class FlowView(common.WWrap): REQ = 0 RESP = 1 - method_options = [ - ("get", "g"), - ("post", "p"), - ("put", "u"), - ("head", "h"), - ("trace", "t"), - ("delete", "d"), - ("options", "o"), - ("edit raw", "e"), - ] highlight_color = "focusfield" @@ -504,7 +494,7 @@ class FlowView(common.WWrap): if m == "e": self.master.prompt_edit("Method", self.flow.request.method, self.set_method_raw) else: - for i in self.method_options: + for i in common.METHOD_OPTIONS: if i[1] == m: self.flow.request.method = i[0].upper() self.master.refresh_flow(self.flow) @@ -599,7 +589,7 @@ class FlowView(common.WWrap): elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: self.master.prompt_edit("URL", message.url, self.set_url) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_onekey("Method", self.method_options, self.edit_method) + self.master.prompt_onekey("Method", common.METHOD_OPTIONS, self.edit_method) elif part == "c" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: self.master.prompt_edit("Code", str(message.code), self.set_resp_code) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 49ec5a0b..d96b9b8c 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -763,6 +763,15 @@ class FlowMaster(controller.Master): def duplicate_flow(self, f): return self.load_flow(f.copy()) + def add_request(self, method, scheme, host, port, path): + f = http.HTTPFlow(None,None); + headers = ODictCaseless() + + req = http.HTTPRequest("relative", method, scheme, host, port, path, (1, 1), headers, None, + None, None, None) + f.request = req + return self.load_flow(f) + def load_flow(self, f): """ Loads a flow, and returns a new flow object. -- cgit v1.2.3 From 80da33b2d322d23f8958d6e6c81cad6ae9c5349b Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 10 Feb 2015 15:45:11 -0300 Subject: request is absolute --- libmproxy/flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index d96b9b8c..e9d90916 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -767,7 +767,7 @@ class FlowMaster(controller.Master): f = http.HTTPFlow(None,None); headers = ODictCaseless() - req = http.HTTPRequest("relative", method, scheme, host, port, path, (1, 1), headers, None, + req = http.HTTPRequest("absolute", method, scheme, host, port, path, (1, 1), headers, None, None, None, None) f.request = req return self.load_flow(f) -- cgit v1.2.3 From 1df78f75c5ceb368ca9ba9d1b01e17af21cab892 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Tue, 10 Feb 2015 17:18:23 -0300 Subject: set sni to None when no server_conn is None --- libmproxy/protocol/http.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 2f858a7c..79a4bf74 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -1457,9 +1457,11 @@ class RequestReplayThread(threading.Thread): server = ServerConnection(server_address) server.connect() if r.scheme == "https": - server.establish_ssl(self.config.clientcerts, sni=self.flow.server_conn.sni) + sni = None + if self.flow.server_conn: + sni = self.flow.server_conn.sni + server.establish_ssl(self.config.clientcerts, sni=sni) r.form_out = "relative" - server.send(r.assemble()) self.flow.server_conn = server self.flow.response = HTTPResponse.from_stream(server.rfile, r.method, -- cgit v1.2.3 From 493cecfaf27f7680c8acaaa88a467fc016a00bf8 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 11 Feb 2015 16:05:49 -0300 Subject: renamed add_request to create_request and added a tiny docstring --- libmproxy/console/flowlist.py | 2 +- libmproxy/flow.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 8dfaba95..7d511682 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -267,7 +267,7 @@ class FlowListBox(urwid.ListBox): def new_request(self, url, method): try: scheme, host, port, path = http.parse_url(url) - f = self.master.add_request(method, scheme, host, port, path) + f = self.master.create_request(method, scheme, host, port, path) self.master.view_flow(f) except ValueError: self.master.statusbar.message("Invalid Url") diff --git a/libmproxy/flow.py b/libmproxy/flow.py index e9d90916..42fc36cc 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -763,7 +763,13 @@ class FlowMaster(controller.Master): def duplicate_flow(self, f): return self.load_flow(f.copy()) - def add_request(self, method, scheme, host, port, path): + def create_request(self, method, scheme, host, port, path): + """ + Creates a new request from params and add it to flow list. + created request is empty (except for method and url) but is able + to be replayed + + """ f = http.HTTPFlow(None,None); headers = ODictCaseless() -- cgit v1.2.3 From 27a1947599f33e7c57c185231f7e623a8b2d4dee Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Wed, 11 Feb 2015 22:03:57 -0300 Subject: missing str in http.parse_url --- libmproxy/console/flowlist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 7d511682..92d58d11 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -266,7 +266,7 @@ class FlowListBox(urwid.ListBox): def new_request(self, url, method): try: - scheme, host, port, path = http.parse_url(url) + scheme, host, port, path = http.parse_url(str(url)) f = self.master.create_request(method, scheme, host, port, path) self.master.view_flow(f) except ValueError: -- cgit v1.2.3 From 16653cc62be4109cd465594ca2f5226d954027f2 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 12 Feb 2015 00:31:05 -0300 Subject: fixed typos --- libmproxy/console/flowlist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 92d58d11..cd866819 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -17,7 +17,7 @@ def _mkhelp(): ("g", "copy flow to clipboard"), ("l", "set limit filter pattern"), ("L", "load saved flows"), - ("n", "creates a new request"), + ("n", "create a new request"), ("r", "replay request"), ("V", "revert changes to request"), ("w", "save flows "), @@ -262,7 +262,7 @@ class FlowListBox(urwid.ListBox): self.get_url(method) def get_url(self,method): - self.master.prompt("Url:", "http://www.example.com/", self.new_request, method) + self.master.prompt("URL:", "http://www.example.com/", self.new_request, method) def new_request(self, url, method): try: -- cgit v1.2.3 From 58091b704111b3192693f1af763888c50c68a481 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 12 Feb 2015 01:33:35 -0300 Subject: removed useless try except --- libmproxy/console/flowlist.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index cd866819..9e7c6d69 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -265,12 +265,13 @@ class FlowListBox(urwid.ListBox): self.master.prompt("URL:", "http://www.example.com/", self.new_request, method) def new_request(self, url, method): - try: - scheme, host, port, path = http.parse_url(str(url)) - f = self.master.create_request(method, scheme, host, port, path) - self.master.view_flow(f) - except ValueError: + parts = http.parse_url(str(url)) + if not parts: self.master.statusbar.message("Invalid Url") + return + scheme, host, port, path = parts + f = self.master.create_request(method, scheme, host, port, path) + self.master.view_flow(f) def keypress(self, size, key): key = common.shortcuts(key) -- cgit v1.2.3 From fbba6bfe06c79c44ef1947baeb3344dccc8aa483 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 12 Feb 2015 01:42:48 -0300 Subject: added ClientConnection and ServerConnection to new request --- libmproxy/flow.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 42fc36cc..1870761f 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -8,12 +8,13 @@ import Cookie import cookielib import os import re -from netlib import odict, wsgi +from netlib import odict, wsgi, tcp import netlib.http from . import controller, protocol, tnetstring, filt, script, version from .onboarding import app from .protocol import http, handle from .proxy.config import HostMatcher +from .proxy.connection import ClientConnection, ServerConnection import urlparse ODict = odict.ODict @@ -768,9 +769,19 @@ class FlowMaster(controller.Master): Creates a new request from params and add it to flow list. created request is empty (except for method and url) but is able to be replayed - """ - f = http.HTTPFlow(None,None); + c = ClientConnection.from_state(dict( + address=dict(address=(host, port), use_ipv6=False), + clientcert=None + )) + + s = ServerConnection.from_state(dict( + address=dict(address=(host, port), use_ipv6=False), + state=[], + source_address=None, #source_address=dict(address=(host, port), use_ipv6=False), + cert=None + )) + f = http.HTTPFlow(c,s); headers = ODictCaseless() req = http.HTTPRequest("absolute", method, scheme, host, port, path, (1, 1), headers, None, -- cgit v1.2.3 From 71a58289e27bed18ca40bd9e62d67cff10467dc0 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 12 Feb 2015 01:52:13 -0300 Subject: less is more --- libmproxy/flow.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 1870761f..3c5ac1fe 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -766,9 +766,7 @@ class FlowMaster(controller.Master): def create_request(self, method, scheme, host, port, path): """ - Creates a new request from params and add it to flow list. - created request is empty (except for method and url) but is able - to be replayed + this method creates a new artificial and minimalist request also adds it to flowlist """ c = ClientConnection.from_state(dict( address=dict(address=(host, port), use_ipv6=False), -- cgit v1.2.3 From 010b921a93b2c7e3d6b26ca0db4538a56d7c8fb0 Mon Sep 17 00:00:00 2001 From: Marcelo Glezer Date: Thu, 12 Feb 2015 13:41:58 -0300 Subject: added sni and ssl_established=true in ServerConnection. removed check for None value of server_conn in http.py --- libmproxy/flow.py | 4 +++- libmproxy/protocol/http.py | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 3c5ac1fe..14497964 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -777,7 +777,9 @@ class FlowMaster(controller.Master): address=dict(address=(host, port), use_ipv6=False), state=[], source_address=None, #source_address=dict(address=(host, port), use_ipv6=False), - cert=None + cert=None, + sni=host, + ssl_established=True )) f = http.HTTPFlow(c,s); headers = ODictCaseless() diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 79a4bf74..046d0b42 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -1457,10 +1457,7 @@ class RequestReplayThread(threading.Thread): server = ServerConnection(server_address) server.connect() if r.scheme == "https": - sni = None - if self.flow.server_conn: - sni = self.flow.server_conn.sni - server.establish_ssl(self.config.clientcerts, sni=sni) + server.establish_ssl(self.config.clientcerts, sni=self.flow.server_conn.sni) r.form_out = "relative" server.send(r.assemble()) self.flow.server_conn = server -- cgit v1.2.3