summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/using-monkey.md9
-rw-r--r--frontends/monkey/401login.c3
-rw-r--r--test/monkeyfarmer.py89
3 files changed, 99 insertions, 2 deletions
diff --git a/docs/using-monkey.md b/docs/using-monkey.md
index f4cb9d66a..b9155746a 100644
--- a/docs/using-monkey.md
+++ b/docs/using-monkey.md
@@ -138,10 +138,14 @@ Commands
Cause a login to proceed using the set credentials
+ This will send a `DESTROY` message back.
+
* `LOGIN DESTROY` _%id%_
Cause a login to fail
+ This will send a `DESTROY` message back.
+
Responses
---------
@@ -378,6 +382,11 @@ Responses
Subsequent to this message, the user of monkey is at liberty to issue
`LOGIN` commands to control the response of the `401LOGIN` process.
+* `LOGIN DESTROY LWIN` _%id%_
+
+ The given login window has been destroyed and should no longer be sent
+ commands otherwise undefined behaviour may ensue.
+
### Plotter messages
> **Note, Monkey won't clip coordinates, but sometimes the core does.**
diff --git a/frontends/monkey/401login.c b/frontends/monkey/401login.c
index 00913156a..b9e75bf8f 100644
--- a/frontends/monkey/401login.c
+++ b/frontends/monkey/401login.c
@@ -94,6 +94,7 @@ monkey_find_login_by_num(uint32_t login_num)
}
static void free_login_context(struct monkey401 *m401_ctx) {
+ moutf(MOUT_LOGIN, "DESTROY LWIN %u", m401_ctx->num);
RING_REMOVE(m401_ring, m401_ctx);
if (m401_ctx->username != NULL) {
free(m401_ctx->username);
@@ -121,7 +122,7 @@ monkey_login_handle_go(int argc, char **argv)
}
m401_ctx->cb(m401_ctx->username, m401_ctx->password, m401_ctx->cbpw);
-
+
free_login_context(m401_ctx);
}
diff --git a/test/monkeyfarmer.py b/test/monkeyfarmer.py
index 239a63e0e..b5d969e7c 100644
--- a/test/monkeyfarmer.py
+++ b/test/monkeyfarmer.py
@@ -125,6 +125,7 @@ class Browser:
def __init__(self, monkey_cmd=["./nsmonkey"], quiet=False):
self.farmer = MonkeyFarmer(monkey_cmd=monkey_cmd, online=self.on_monkey_line, quiet=quiet)
self.windows = {}
+ self.logins = {}
self.current_draw_target = None
self.started = False
self.stopped = False
@@ -175,6 +176,19 @@ class Browser:
else:
win.handle(action, *args)
+ def handle_LOGIN(self, action, _lwin, winid, *args):
+ if action == "OPEN":
+ new_win = LoginWindow(self, winid, *args)
+ self.logins[winid] = new_win
+ else:
+ win = self.logins.get(winid, None)
+ if win is None:
+ print(" Unknown login window id {}".format(winid))
+ else:
+ win.handle(action, *args)
+ if win.alive and win.ready:
+ self.handle_ready_login(win)
+
def handle_PLOT(self, *args):
if self.current_draw_target is not None:
self.current_draw_target.handle_plot(*args)
@@ -189,8 +203,63 @@ class Browser:
self.farmer.loop(once=True)
poss_wins = set(self.windows.keys()).difference(wins_known)
return self.windows[poss_wins.pop()]
+
+ def handle_ready_login(self, lwin):
+ # Override this method to do useful stuff
+ lwin.destroy()
+
+class LoginWindow:
+ def __init__(self, browser, winid, _url, *url):
+ self.alive = True
+ self.ready = False
+ self.browser = browser
+ self.winid = winid
+ self.url = " ".join(url)
+ self.username = None
+ self.password = None
+ self.realm = None
+
+ def handle(self, action, _str="STR", *rest):
+ content = " ".join(rest)
+ if action == "USER":
+ self.username = content
+ elif action == "PASS":
+ self.password = content
+ elif action == "REALM":
+ self.realm = content
+ elif action == "DESTROY":
+ self.alive = False
+ else:
+ raise AssertionError("Unknown action {} for login window".format(action))
+ if not (self.username is None or self.password is None or self.realm is None):
+ self.ready = True
+
+ def send_username(self, username=None):
+ assert(self.alive)
+ if username is None:
+ username = self.username
+ self.browser.farmer.tell_monkey("LOGIN USERNAME {} {}".format(self.winid, username))
+
+ def send_password(self, password=None):
+ assert(self.alive)
+ if password is None:
+ password = self.password
+ self.browser.farmer.tell_monkey("LOGIN PASSWORD {} {}".format(self.winid, password))
+
+ def _wait_dead(self):
+ while self.alive:
+ self.browser.farmer.loop(once=True)
+
+ def go(self):
+ assert(self.alive)
+ self.browser.farmer.tell_monkey("LOGIN GO {}".format(self.winid))
+ self._wait_dead()
+
+ def destroy(self):
+ assert(self.alive)
+ self.browser.farmer.tell_monkey("LOGIN DESTROY {}".format(self.winid))
+ self._wait_dead()
-
class BrowserWindow:
def __init__(self, browser, winid, _for, coreid, _existing, otherid, _newtab, newtab, _clone, clone):
self.alive = True
@@ -385,6 +454,24 @@ if __name__ == '__main__':
browser.quit_and_wait()
+ class FooBarLogin(Browser):
+ def handle_ready_login(self, lwin):
+ lwin.send_username("foo")
+ lwin.send_password("bar")
+ lwin.go()
+
+ browser = FooBarLogin(quiet=True)
+ win = browser.new_window()
+ win.load_page("https://httpbin.org/basic-auth/foo/bar")
+ cmds = win.redraw()
+
+ for cmd in cmds:
+ if cmd[0] == "TEXT":
+ x = cmd[2]
+ y = cmd[4]
+ rest = " ".join(cmd[6:])
+ print("{} {} -> {}".format(x,y,rest))
+
#print("Discussion was:")
#for line in browser.farmer.discussion:
# print("{} {}".format(line[0], line[1]))