|
1 |
| -use bytes::{BufMut, BytesMut}; |
| 1 | +use bytes::{Buf, BufMut, BytesMut}; |
2 | 2 | use md5::{Digest, Md5};
|
3 | 3 | use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
|
4 | 4 | use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
5 | 5 | use tokio::net::TcpStream;
|
6 | 6 |
|
| 7 | +use std::collections::HashMap; |
| 8 | + |
7 | 9 | use crate::errors::Error;
|
8 | 10 |
|
9 | 11 | // This is a funny one. `psql` parses this to figure out which
|
@@ -105,6 +107,51 @@ pub async fn startup(stream: &mut TcpStream, user: &str, database: &str) -> Resu
|
105 | 107 | }
|
106 | 108 | }
|
107 | 109 |
|
| 110 | +/// Parse StartupMessage parameters. |
| 111 | +/// e.g. user, database, application_name, etc. |
| 112 | +pub fn parse_startup(mut bytes: BytesMut) -> Result<HashMap<String, String>, Error> { |
| 113 | + let mut result = HashMap::new(); |
| 114 | + let mut buf = Vec::new(); |
| 115 | + let mut tmp = String::new(); |
| 116 | + |
| 117 | + while bytes.has_remaining() { |
| 118 | + let mut c = bytes.get_u8(); |
| 119 | + |
| 120 | + // Null-terminated C-strings. |
| 121 | + while c != 0 { |
| 122 | + tmp.push(c as char); |
| 123 | + c = bytes.get_u8(); |
| 124 | + } |
| 125 | + |
| 126 | + if tmp.len() > 0 { |
| 127 | + buf.push(tmp.clone()); |
| 128 | + tmp.clear(); |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + // Expect pairs of name and value |
| 133 | + // and at least one pair to be present. |
| 134 | + if buf.len() % 2 != 0 && buf.len() >= 2 { |
| 135 | + return Err(Error::ClientBadStartup); |
| 136 | + } |
| 137 | + |
| 138 | + let mut i = 0; |
| 139 | + while i < buf.len() { |
| 140 | + let name = buf[i].clone(); |
| 141 | + let value = buf[i + 1].clone(); |
| 142 | + let _ = result.insert(name, value); |
| 143 | + i += 2; |
| 144 | + } |
| 145 | + |
| 146 | + // Minimum required parameters |
| 147 | + // I want to have the user at the very minimum, according to the protocol spec. |
| 148 | + if !result.contains_key("user") { |
| 149 | + return Err(Error::ClientBadStartup); |
| 150 | + } |
| 151 | + |
| 152 | + Ok(result) |
| 153 | +} |
| 154 | + |
108 | 155 | /// Send password challenge response to the server.
|
109 | 156 | /// This is the MD5 challenge.
|
110 | 157 | pub async fn md5_password(
|
|
0 commit comments